/// <summary>
        /// Builds the restrictions for calling with a splatted argument array.  Ensures that the
        /// argument is still an ICollection of object and that it has the same number of arguments.
        /// </summary>
        private static BindingRestrictions MakeParamsTest(DynamicMetaObject splattee, bool testTypes)
        {
            IList <object> list = splattee.Value as IList <object>;

            if (list == null)
            {
                if (splattee.Value == null)
                {
                    return(BindingRestrictions.GetExpressionRestriction(Ast.Equal(splattee.Expression, AstUtils.Constant(null))));
                }
                else
                {
                    return(BindingRestrictions.GetTypeRestriction(splattee.Expression, splattee.Value.GetType()));
                }
            }

            BindingRestrictions res = BindingRestrictions.GetExpressionRestriction(
                Ast.AndAlso(
                    Ast.TypeIs(splattee.Expression, typeof(IList <object>)),
                    Ast.Equal(
                        Ast.Property(
                            Ast.Convert(splattee.Expression, typeof(IList <object>)),
                            typeof(ICollection <object>).GetDeclaredProperty("Count")
                            ),
                        AstUtils.Constant(list.Count)
                        )
                    )
                );

            if (testTypes)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    res = res.Merge(
                        BindingRestrictionsHelpers.GetRuntimeTypeRestriction(
                            Ast.Call(
                                AstUtils.Convert(
                                    splattee.Expression,
                                    typeof(IList <object>)
                                    ),
                                typeof(IList <object>).GetMethod("get_Item"),
                                AstUtils.Constant(i)
                                ),
                            CompilerHelpers.GetType(list[i])
                            )
                        );
                }
            }

            return(res);
        }
        /// <summary>
        /// Produces a rule for comparing a value to null - supports comparing object references and nullable types.
        /// </summary>
        private static DynamicMetaObject TryNullComparisonRule(DynamicMetaObject[] args)
        {
            Type otherType = args[1].GetLimitType();

            BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[0].Expression, args[0].GetLimitType()).Merge(BindingRestrictions.Combine(args));

            if (args[0].GetLimitType() == typeof(DynamicNull))
            {
                if (!otherType.IsValueType)
                {
                    return(new DynamicMetaObject(
                               Expression.Equal(args[0].Expression, AstUtils.Constant(null)),
                               restrictions
                               ));
                }

                if (otherType.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    return(new DynamicMetaObject(
                               Expression.Property(args[0].Expression, otherType.GetDeclaredProperty("HasValue")),
                               restrictions
                               ));
                }
            }
            else if (otherType == typeof(DynamicNull))
            {
                if (!args[0].GetLimitType().IsValueType)
                {
                    return(new DynamicMetaObject(
                               Expression.Equal(args[0].Expression, AstUtils.Constant(null)),
                               restrictions
                               ));
                }

                if (args[0].GetLimitType().GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    return(new DynamicMetaObject(
                               Expression.Property(args[0].Expression, otherType.GetDeclaredProperty("HasValue")),
                               restrictions
                               ));
                }
            }
            return(null);
        }
        public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
        {
            Expression[] exprs = new Expression[args.Length + 1];
            exprs[0] = Expression.Constant("FallbackInvoke");
            for (int i = 0; i < args.Length; i++)
            {
                exprs[i + 1] = args[i].Expression;
            }

            return(new DynamicMetaObject(
                       Expression.Call(
                           typeof(String).GetMethod("Concat", new Type[] { typeof(object[]) }),
                           Expression.NewArrayInit(
                               typeof(object),
                               exprs
                               )
                           ),
                       BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target)
                       ));
        }
        public override DynamicMetaObject FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
        {
            var newTarget = new DynamicMetaObject(Expression.Convert(target.Expression, target.LimitType), BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType), target.Value);
            var exp       = TryConvertExpression(newTarget.Expression, Type, null);

            if (exp == null)
            {
                exp = Expression.Throw(Expression.Constant(new InvalidCastException()), Type);
            }
            if (ReturnType != Type)
            {
                exp = Expression.Convert(exp, ReturnType);
            }
            var ret = _context.Binder.ConvertTo(
                Type,
                Explicit ? Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast : Microsoft.Scripting.Actions.ConversionResultKind.ImplicitCast,
                newTarget,
                new TjsOverloadResolverFactory(_context.Binder),
                new DynamicMetaObject(exp, BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target))
                );

            return(ret);
        }
        private static DynamicMetaObject TryMakeDefaultUnaryRule(OperatorInfo info, DynamicMetaObject[] args)
        {
            if (args.Length == 1)
            {
                BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[0].Expression, args[0].GetLimitType()).Merge(BindingRestrictions.Combine(args));
                switch (info.Operator)
                {
                case ExpressionType.IsTrue:
                    if (args[0].GetLimitType() == typeof(bool))
                    {
                        return(args[0]);
                    }
                    break;

                case ExpressionType.Negate:
                    if (args[0].GetLimitType().IsArithmetic())
                    {
                        return(new DynamicMetaObject(
                                   Expression.Negate(args[0].Expression),
                                   restrictions
                                   ));
                    }
                    break;

                case ExpressionType.Not:
                    if (args[0].GetLimitType().IsIntegerOrBool())
                    {
                        return(new DynamicMetaObject(
                                   Expression.Not(args[0].Expression),
                                   restrictions
                                   ));
                    }
                    break;
                }
            }
            return(null);
        }
Exemple #6
0
        public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
        {
            var restrictions = target.Restrictions.Merge(
                BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target));

            //target = target.Restrict(target.RuntimeType);
            //args = args.Select(o => o.Restrict(o.RuntimeType)).ToArray();

            MethodBase targetMethod;

            switch (Name)
            {
            case "SelectMany":
                targetMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(
                    o => o.Name == Name).Skip(3).First().MakeGenericMethod(
                    typeof(object), typeof(object), typeof(object));
                break;

            default:
                targetMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(
                    o => o.Name == Name).First().MakeGenericMethod(
                    typeof(object), typeof(object));
                break;
            }

            foreach (var o in args)
            {
                restrictions = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(o));
            }

            return(_binder.CallMethod(
                       new DefaultOverloadResolver(_binder, target, args.ToList(), new CallSignature(args.Length)),
                       new[] { targetMethod },
                       restrictions,
                       Name));
        }
Exemple #7
0
        internal static DynamicMetaObject TranslateArguments(DynamicMetaObjectBinder call, Expression codeContext, DynamicMetaObject function, DynamicMetaObject /*!*/[] args, bool hasSelf, string name)
        {
            if (hasSelf)
            {
                args = ArrayUtils.RemoveFirst(args);
            }

            CallSignature sig = BindingHelpers.GetCallSignature(call);

            if (sig.HasDictionaryArgument())
            {
                int index = sig.IndexOf(ArgumentType.Dictionary);

                DynamicMetaObject dict = args[index];

                if (!(dict.Value is IDictionary) && dict.Value != null)
                {
                    // The DefaultBinder only handles types that implement IDictionary.  Here we have an
                    // arbitrary user-defined mapping type.  We'll convert it into a PythonDictionary
                    // and then have an embedded dynamic site pass that dictionary through to the default
                    // binder.
                    DynamicMetaObject[] dynamicArgs = ArrayUtils.Insert(function, args);

                    dynamicArgs[index + 1] = new DynamicMetaObject(
                        Expression.Call(
                            typeof(PythonOps).GetMethod(nameof(PythonOps.UserMappingToPythonDictionary)),
                            codeContext,
                            args[index].Expression,
                            AstUtils.Constant(name)
                            ),
                        BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType()),
                        PythonOps.UserMappingToPythonDictionary(PythonContext.GetPythonContext(call).SharedContext, dict.Value, name)
                        );

                    if (call is IPythonSite)
                    {
                        dynamicArgs = ArrayUtils.Insert(
                            new DynamicMetaObject(codeContext, BindingRestrictions.Empty),
                            dynamicArgs
                            );
                    }

                    return(new DynamicMetaObject(
                               DynamicExpression.Dynamic(
                                   call,
                                   typeof(object),
                                   DynamicUtils.GetExpressions(dynamicArgs)
                                   ),
                               BindingRestrictions.Combine(dynamicArgs).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType()))
                               ));
                }
            }

            if (sig.HasListArgument())
            {
                int index             = sig.IndexOf(ArgumentType.List);
                DynamicMetaObject str = args[index];

                // TODO: ANything w/ __iter__ that's not an IList<object>
                if (!(str.Value is IList <object>) && str.Value is IEnumerable)
                {
                    // The DefaultBinder only handles types that implement IList<object>.  Here we have a
                    // string.  We'll convert it into a tuple
                    // and then have an embedded dynamic site pass that tuple through to the default
                    // binder.
                    DynamicMetaObject[] dynamicArgs = ArrayUtils.Insert(function, args);

                    dynamicArgs[index + 1] = new DynamicMetaObject(
                        Expression.Call(
                            typeof(PythonOps).GetMethod(nameof(PythonOps.MakeTupleFromSequence)),
                            Expression.Convert(args[index].Expression, typeof(object))
                            ),
                        BindingRestrictions.Empty
                        );

                    if (call is IPythonSite)
                    {
                        dynamicArgs = ArrayUtils.Insert(
                            new DynamicMetaObject(codeContext, BindingRestrictions.Empty),
                            dynamicArgs
                            );
                    }

                    return(new DynamicMetaObject(
                               DynamicExpression.Dynamic(
                                   call,
                                   typeof(object),
                                   DynamicUtils.GetExpressions(dynamicArgs)
                                   ),
                               function.Restrictions.Merge(
                                   BindingRestrictions.Combine(args).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(str.Expression, str.GetLimitType()))
                                   )
                               ));
                }
            }
            return(null);
        }
Exemple #8
0
        /// <summary>
        /// Creating a Python type involves calling __new__ and __init__.  We resolve them
        /// and generate calls to either the builtin funcions directly or embed sites which
        /// call the slots at runtime.
        /// </summary>
        private DynamicMetaObject /*!*/ MakePythonTypeCall(DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext, DynamicMetaObject /*!*/[] /*!*/ args)
        {
            ValidationInfo valInfo = MakeVersionCheck();

            DynamicMetaObject self = new RestrictedMetaObject(
                AstUtils.Convert(Expression, LimitType),
                BindingRestrictionsHelpers.GetRuntimeTypeRestriction(Expression, LimitType),
                Value
                );
            CallSignature  sig = BindingHelpers.GetCallSignature(call);
            ArgumentValues ai  = new ArgumentValues(sig, self, args);
            NewAdapter     newAdapter;
            InitAdapter    initAdapter;

            if (TooManyArgsForDefaultNew(call, args))
            {
                return(MakeIncorrectArgumentsForCallError(call, ai, valInfo));
            }
            else if (Value.UnderlyingSystemType.IsGenericTypeDefinition)
            {
                return(MakeGenericTypeDefinitionError(call, ai, valInfo));
            }
            else if (Value.HasAbstractMethods(PythonContext.GetPythonContext(call).SharedContext))
            {
                return(MakeAbstractInstantiationError(call, ai, valInfo));
            }

            DynamicMetaObject translated = BuiltinFunction.TranslateArguments(call, codeContext, self, args, false, Value.Name);

            if (translated != null)
            {
                return(translated);
            }

            GetAdapters(ai, call, codeContext, out newAdapter, out initAdapter);
            PythonContext state = PythonContext.GetPythonContext(call);

            // get the expression for calling __new__
            DynamicMetaObject createExpr = newAdapter.GetExpression(state.Binder);

            if (createExpr.Expression.Type == typeof(void))
            {
                return(BindingHelpers.AddDynamicTestAndDefer(
                           call,
                           createExpr,
                           args,
                           valInfo
                           ));
            }

            Expression          res;
            BindingRestrictions additionalRestrictions = BindingRestrictions.Empty;

            if (!Value.IsSystemType && (!(newAdapter is DefaultNewAdapter) || HasFinalizer(call)))
            {
                // we need to dynamically check the return value to see if it's a subtype of
                // the type that we are calling.  If it is then we need to call __init__/__del__
                // for the actual returned type.
                res = Expression.Dynamic(
                    Value.GetLateBoundInitBinder(sig),
                    typeof(object),
                    ArrayUtils.Insert(
                        codeContext,
                        Expression.Convert(createExpr.Expression, typeof(object)),
                        DynamicUtils.GetExpressions(args)
                        )
                    );
                additionalRestrictions = createExpr.Restrictions;
            }
            else
            {
                // just call the __init__ method, built-in types currently have
                // no wacky return values which don't return the derived type.

                // then get the statement for calling __init__
                ParameterExpression allocatedInst = Ast.Variable(createExpr.GetLimitType(), "newInst");
                Expression          tmpRead       = allocatedInst;
                DynamicMetaObject   initCall      = initAdapter.MakeInitCall(
                    state.Binder,
                    new RestrictedMetaObject(
                        AstUtils.Convert(allocatedInst, Value.UnderlyingSystemType),
                        createExpr.Restrictions
                        )
                    );

                List <Expression> body = new List <Expression>();
                Debug.Assert(!HasFinalizer(call));

                // add the call to init if we need to
                if (initCall.Expression != tmpRead)
                {
                    // init can fail but if __new__ returns a different type
                    // no exception is raised.
                    DynamicMetaObject initStmt = initCall;

                    if (body.Count == 0)
                    {
                        body.Add(
                            Ast.Assign(allocatedInst, createExpr.Expression)
                            );
                    }

                    if (!Value.UnderlyingSystemType.IsAssignableFrom(createExpr.Expression.Type))
                    {
                        // return type of object, we need to check the return type before calling __init__.
                        body.Add(
                            AstUtils.IfThen(
                                Ast.TypeIs(allocatedInst, Value.UnderlyingSystemType),
                                initStmt.Expression
                                )
                            );
                    }
                    else
                    {
                        // just call the __init__ method, no type check necessary (TODO: need null check?)
                        body.Add(initStmt.Expression);
                    }
                }

                // and build the target from everything we have
                if (body.Count == 0)
                {
                    res = createExpr.Expression;
                }
                else
                {
                    body.Add(allocatedInst);
                    res = Ast.Block(body);
                }
                res = Ast.Block(new ParameterExpression[] { allocatedInst }, res);

                additionalRestrictions = initCall.Restrictions;
            }

            return(BindingHelpers.AddDynamicTestAndDefer(
                       call,
                       new DynamicMetaObject(
                           res,
                           self.Restrictions.Merge(additionalRestrictions)
                           ),
                       ArrayUtils.Insert(this, args),
                       valInfo
                       ));
        }
        private static DynamicMetaObject TryPrimitiveCompare(OperatorInfo info, DynamicMetaObject[] args)
        {
            if (args[0].GetLimitType().GetNonNullableType() == args[1].GetLimitType().GetNonNullableType() &&
                args[0].GetLimitType().IsNumeric())
            {
                Expression arg0 = args[0].Expression;
                Expression arg1 = args[1].Expression;

                // TODO: Nullable<PrimitveType> Support
                Expression expr;
                switch (info.Operator)
                {
                case ExpressionType.Equal: expr = Expression.Equal(arg0, arg1); break;

                case ExpressionType.NotEqual: expr = Expression.NotEqual(arg0, arg1); break;

                case ExpressionType.GreaterThan: expr = Expression.GreaterThan(arg0, arg1); break;

                case ExpressionType.LessThan: expr = Expression.LessThan(arg0, arg1); break;

                case ExpressionType.GreaterThanOrEqual: expr = Expression.GreaterThanOrEqual(arg0, arg1); break;

                case ExpressionType.LessThanOrEqual: expr = Expression.LessThanOrEqual(arg0, arg1); break;

                default: throw new InvalidOperationException();
                }

                return(new DynamicMetaObject(
                           expr,
                           BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg0, args[0].GetLimitType()).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg1, args[0].GetLimitType())).Merge(BindingRestrictions.Combine(args))
                           ));
            }

            return(null);
        }
Exemple #10
0
        private DynamicMetaObject /*!*/ MakeSelfCall(DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext, DynamicMetaObject /*!*/[] /*!*/ args)
        {
            BindingRestrictions selfRestrict = Restrictions.Merge(
                BindingRestrictionsHelpers.GetRuntimeTypeRestriction(
                    Expression,
                    LimitType
                    )
                ).Merge(
                BindingRestrictions.GetExpressionRestriction(
                    Value.MakeBoundFunctionTest(
                        AstUtils.Convert(Expression, typeof(BuiltinFunction))
                        )
                    )
                );

            Expression instance = Ast.Call(
                typeof(PythonOps).GetMethod("GetBuiltinFunctionSelf"),
                AstUtils.Convert(
                    Expression,
                    typeof(BuiltinFunction)
                    )
                );

            DynamicMetaObject self = GetInstance(instance, CompilerHelpers.GetType(Value.BindingSelf));

            return(Value.MakeBuiltinFunctionCall(
                       call,
                       codeContext,
                       this,
                       ArrayUtils.Insert(self, args),
                       true, // has self
                       selfRestrict,
                       (newArgs) => {
                CallSignature signature = BindingHelpers.GetCallSignature(call);
                DynamicMetaObject res;
                PythonContext state = PythonContext.GetPythonContext(call);
                BindingTarget target;
                PythonOverloadResolver resolver;
                if (Value.IsReversedOperator)
                {
                    resolver = new PythonOverloadResolver(
                        state.Binder,
                        newArgs,
                        GetReversedSignature(signature),
                        codeContext
                        );
                }
                else
                {
                    resolver = new PythonOverloadResolver(
                        state.Binder,
                        self,
                        args,
                        signature,
                        codeContext
                        );
                }

                res = state.Binder.CallMethod(
                    resolver,
                    Value.Targets,
                    self.Restrictions,
                    Value.Name,
                    NarrowingLevel.None,
                    Value.IsBinaryOperator ? PythonNarrowing.BinaryOperator : NarrowingLevel.All,
                    out target
                    );

                return BindingHelpers.CheckLightThrow(call, res, target);
            }
                       ));
        }
        private DynamicMetaObject /*!*/ GetInstance(Expression /*!*/ instance, Type /*!*/ testType)
        {
            Assert.NotNull(instance, testType);
            object instanceValue = Value.BindingSelf;

            BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(instance, testType);

            // cast the instance to the correct type
            if (CompilerHelpers.IsStrongBox(instanceValue))
            {
                instance      = ReadStrongBoxValue(instance);
                instanceValue = ((IStrongBox)instanceValue).Value;
            }
            else if (!testType.IsEnum)
            {
                // We need to deal w/ wierd types like MarshalByRefObject.
                // We could have an MBRO whos DeclaringType is completely different.
                // Therefore we special case it here and cast to the declaring type

                Type selfType = CompilerHelpers.GetType(Value.BindingSelf);
                selfType = CompilerHelpers.GetVisibleType(selfType);

                if (selfType == typeof(object) && Value.DeclaringType.IsInterface)
                {
                    selfType = Value.DeclaringType;
                }

                if (Value.DeclaringType.IsInterface && selfType.IsValueType)
                {
                    // explicit interface implementation dispatch on a value type, don't
                    // unbox the value type before the dispatch.
                    instance = AstUtils.Convert(instance, Value.DeclaringType);
                }
                else if (selfType.IsValueType)
                {
                    // We might be calling a a mutating method (like
                    // Rectangle.Intersect). If so, we want it to mutate
                    // the boxed value directly
                    instance = Ast.Unbox(instance, selfType);
                }
                else
                {
#if SILVERLIGHT
                    instance = AstUtils.Convert(instance, selfType);
#else
                    Type convType = selfType == typeof(MarshalByRefObject) ? CompilerHelpers.GetVisibleType(Value.DeclaringType) : selfType;

                    instance = AstUtils.Convert(instance, convType);
#endif
                }
            }
            else
            {
                // we don't want to cast the enum to its real type, it will unbox it
                // and turn it into its underlying type.  We presumably want to call
                // a method on the Enum class though - so we cast to Enum instead.
                instance = AstUtils.Convert(instance, typeof(Enum));
            }
            return(new DynamicMetaObject(
                       instance,
                       restrictions,
                       instanceValue
                       ));
        }
Exemple #12
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));
            }
        }
        public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion)
        {
            var        left  = Expression.Convert(target.Expression, target.LimitType);
            var        right = Expression.Convert(arg.Expression, arg.LimitType);
            Expression res   = null;

            switch (Operation)
            {
            case ExpressionType.Add:
                if (target.LimitType == typeof(string) || arg.LimitType == typeof(string))
                {
                    res = Expression.Call(new Func <string, string, string>(string.Concat).Method, _context.Convert(left, typeof(string)), _context.Convert(right, typeof(string)));
                }
                else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType))
                {
                    res = Expression.Add(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double)));
                }
                else
                {
                    res = Expression.Add(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long)));
                }
                break;

            case ExpressionType.And:
                res = Expression.And(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long)));
                break;

            case ExpressionType.Divide:
                res = Expression.Divide(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double)));
                break;

            case ExpressionType.Equal:
                res = Expression.Condition(Equal(left, right), Expression.Constant(1L), Expression.Constant(0L));
                break;

            case ExpressionType.ExclusiveOr:
                res = Expression.ExclusiveOr(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long)));
                break;

            case ExpressionType.GreaterThan:
            {
                Expression exp;
                if (target.LimitType == typeof(string) && arg.LimitType == typeof(string))
                {
                    exp = Expression.GreaterThan(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0));
                }
                else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType))
                {
                    exp = Expression.GreaterThan(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double)));
                }
                else
                {
                    exp = Expression.GreaterThan(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long)));
                }
                res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L));
            }
            break;

            case ExpressionType.GreaterThanOrEqual:
            {
                Expression exp;
                if (target.LimitType == typeof(string) && arg.LimitType == typeof(string))
                {
                    exp = Expression.GreaterThanOrEqual(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0));
                }
                else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType))
                {
                    exp = Expression.GreaterThanOrEqual(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double)));
                }
                else
                {
                    exp = Expression.GreaterThanOrEqual(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long)));
                }
                res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L));
            }
            break;

            case ExpressionType.LeftShift:
                res = Expression.LeftShift(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(int)));
                break;

            case ExpressionType.LessThan:
            {
                Expression exp;
                if (target.LimitType == typeof(string) && arg.LimitType == typeof(string))
                {
                    exp = Expression.LessThan(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0));
                }
                else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType))
                {
                    exp = Expression.LessThan(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double)));
                }
                else
                {
                    exp = Expression.LessThan(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long)));
                }
                res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L));
            }
            break;

            case ExpressionType.LessThanOrEqual:
            {
                Expression exp;
                if (target.LimitType == typeof(string) && arg.LimitType == typeof(string))
                {
                    exp = Expression.LessThanOrEqual(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0));
                }
                else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType))
                {
                    exp = Expression.LessThanOrEqual(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double)));
                }
                else
                {
                    exp = Expression.LessThanOrEqual(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long)));
                }
                res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L));
            }
            break;

            case ExpressionType.Modulo:
                res = Expression.Modulo(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long)));
                break;

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

            case ExpressionType.NotEqual:
                res = Expression.Condition(Equal(left, right), Expression.Constant(0L), Expression.Constant(1L));
                break;

            case ExpressionType.Or:
                res = Expression.Or(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long)));
                break;

            case ExpressionType.RightShift:
                res = Expression.RightShift(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(int)));
                break;

            case ExpressionType.Subtract:
                if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType))
                {
                    res = Expression.Subtract(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double)));
                }
                else
                {
                    res = Expression.Subtract(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long)));
                }
                break;
            }
            var restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg));

            if (res != null)
            {
                return(new DynamicMetaObject(Expression.Convert(res, typeof(object)), restrictions));
            }
            else
            {
                return(errorSuggestion ?? new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("不正な二項演算です。")), typeof(object)), restrictions));
            }
        }
Exemple #14
0
        internal DynamicMetaObject FallbackConvert(Type returnType, DynamicMetaObject self, DynamicMetaObject errorSuggestion)
        {
            Type type             = Type;
            DynamicMetaObject res = null;

            switch (Type.GetTypeCode(type))
            {
            case TypeCode.Boolean:
                res = MakeToBoolConversion(self);
                break;

            case TypeCode.Char:
                res = TryToCharConversion(self);
                break;

            case TypeCode.String:
                if (self.GetLimitType() == typeof(Bytes) && !_context.PythonOptions.Python30)
                {
                    res = new DynamicMetaObject(
                        Ast.Call(
                            typeof(PythonOps).GetMethod("MakeString"),
                            AstUtils.Convert(self.Expression, typeof(IList <byte>))
                            ),
                        BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(Bytes))
                        );
                }
                break;

            case TypeCode.Object:
                // !!! Deferral?
                if (type.IsArray && self.Value is PythonTuple && type.GetArrayRank() == 1)
                {
                    res = MakeToArrayConversion(self, type);
                }
                else if (type.IsGenericType && !type.IsAssignableFrom(CompilerHelpers.GetType(self.Value)))
                {
                    Type genTo = type.GetGenericTypeDefinition();

                    // Interface conversion helpers...
                    if (genTo == typeof(IList <>))
                    {
                        if (self.LimitType == typeof(string))
                        {
                            res = new DynamicMetaObject(
                                Ast.Call(
                                    typeof(PythonOps).GetMethod("MakeByteArray"),
                                    AstUtils.Convert(self.Expression, typeof(string))
                                    ),
                                BindingRestrictions.GetTypeRestriction(
                                    self.Expression,
                                    typeof(string)
                                    )
                                );
                        }
                        else
                        {
                            res = TryToGenericInterfaceConversion(self, type, typeof(IList <object>), typeof(ListGenericWrapper <>));
                        }
                    }
                    else if (genTo == typeof(IDictionary <,>))
                    {
                        res = TryToGenericInterfaceConversion(self, type, typeof(IDictionary <object, object>), typeof(DictionaryGenericWrapper <,>));
                    }
                    else if (genTo == typeof(IEnumerable <>))
                    {
                        res = TryToGenericInterfaceConversion(self, type, typeof(IEnumerable), typeof(IEnumerableOfTWrapper <>));
                    }
                }
                else if (type == typeof(IEnumerable))
                {
                    if (!typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self))
                    {
                        res = ConvertToIEnumerable(this, self.Restrict(self.GetLimitType()));
                    }
                }
                else if (type == typeof(IEnumerator))
                {
                    if (!typeof(IEnumerator).IsAssignableFrom(self.GetLimitType()) &&
                        !typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) &&
                        IsIndexless(self))
                    {
                        res = ConvertToIEnumerator(this, self.Restrict(self.GetLimitType()));
                    }
                }
                break;
            }

            if (type.IsEnum && Enum.GetUnderlyingType(type) == self.GetLimitType())
            {
                // numeric type to enum, this is ok if the value is zero
                object value = Activator.CreateInstance(type);

                return(new DynamicMetaObject(
                           Ast.Condition(
                               Ast.Equal(
                                   AstUtils.Convert(self.Expression, Enum.GetUnderlyingType(type)),
                                   AstUtils.Constant(Activator.CreateInstance(self.GetLimitType()))
                                   ),
                               AstUtils.Constant(value),
                               Ast.Call(
                                   typeof(PythonOps).GetMethod("TypeErrorForBadEnumConversion").MakeGenericMethod(type),
                                   AstUtils.Convert(self.Expression, typeof(object))
                                   )
                               ),
                           self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, self.GetLimitType())),
                           value
                           ));
            }

            return(res ?? EnsureReturnType(returnType, Context.Binder.ConvertTo(Type, ResultKind, self, _context.SharedOverloadResolverFactory, errorSuggestion)));
        }
Exemple #15
0
        private DynamicMetaObject /*!*/ GetInstance(Expression /*!*/ instance, Type /*!*/ testType)
        {
            Assert.NotNull(instance, testType);
            object instanceValue = Value.BindingSelf;

            BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(instance, testType);

            // cast the instance to the correct type
            if (CompilerHelpers.IsStrongBox(instanceValue))
            {
                instance      = ReadStrongBoxValue(instance);
                instanceValue = ((IStrongBox)instanceValue).Value;
            }
            else if (!testType.IsEnum)
            {
                // We need to deal w/ wierd types like MarshalByRefObject.
                // We could have an MBRO whos DeclaringType is completely different.
                // Therefore we special case it here and cast to the declaring type

                Type selfType = CompilerHelpers.GetType(Value.BindingSelf);
                selfType = CompilerHelpers.GetVisibleType(selfType);

                if (selfType == typeof(object) && Value.DeclaringType.IsInterface)
                {
                    selfType = Value.DeclaringType;

                    Type genericTypeDefinition = null;
                    if (Value.DeclaringType.IsGenericType &&
                        Value.DeclaringType.FullName == null &&
                        Value.DeclaringType.ContainsGenericParameters &&
                        !Value.DeclaringType.IsGenericTypeDefinition)
                    {
                        // from MSDN: If the current type contains generic type parameters that have not been replaced by
                        // specific types (that is, the ContainsGenericParameters property returns true), but the type
                        // is not a generic type definition (that is, the IsGenericTypeDefinition property returns false),
                        // this property returns Nothing. For example, consider the classes Base and Derived in the following code.

                        // if this type is completely generic (no type arguments specified) then we'll go ahead and get the
                        // generic type definition for the this parameter - that'll let us successfully type infer on it later.
                        var  genericArgs     = Value.DeclaringType.GetGenericArguments();
                        bool hasOnlyGenerics = genericArgs.Length > 0;
                        foreach (var genericParam in genericArgs)
                        {
                            if (!genericParam.IsGenericParameter)
                            {
                                hasOnlyGenerics = false;
                                break;
                            }
                        }
                        if (hasOnlyGenerics)
                        {
                            genericTypeDefinition = Value.DeclaringType.GetGenericTypeDefinition();
                        }
                    }
                    else if (Value.DeclaringType.IsGenericTypeDefinition)
                    {
                        genericTypeDefinition = Value.DeclaringType;
                    }

                    if (genericTypeDefinition != null)
                    {
                        // we're a generic interface method on a non-public type.
                        // We need to see if we can match any types implemented on
                        // the concrete selfType.
                        var interfaces = CompilerHelpers.GetType(Value.BindingSelf).GetInterfaces();
                        foreach (var iface in interfaces)
                        {
                            if (iface.IsGenericType && iface.GetGenericTypeDefinition() == genericTypeDefinition)
                            {
                                selfType = iface;
                                break;
                            }
                        }
                    }
                }

                if (Value.DeclaringType.IsInterface && selfType.IsValueType)
                {
                    // explicit interface implementation dispatch on a value type, don't
                    // unbox the value type before the dispatch.
                    instance = AstUtils.Convert(instance, Value.DeclaringType);
                }
                else if (selfType.IsValueType)
                {
                    // We might be calling a a mutating method (like
                    // Rectangle.Intersect). If so, we want it to mutate
                    // the boxed value directly
                    instance = Ast.Unbox(instance, selfType);
                }
                else
                {
#if SILVERLIGHT
                    instance = AstUtils.Convert(instance, selfType);
#else
                    Type convType = selfType == typeof(MarshalByRefObject) ? CompilerHelpers.GetVisibleType(Value.DeclaringType) : selfType;

                    instance = AstUtils.Convert(instance, convType);
#endif
                }
            }
            else
            {
                // we don't want to cast the enum to its real type, it will unbox it
                // and turn it into its underlying type.  We presumably want to call
                // a method on the Enum class though - so we cast to Enum instead.
                instance = AstUtils.Convert(instance, typeof(Enum));
            }
            return(new DynamicMetaObject(
                       instance,
                       restrictions,
                       instanceValue
                       ));
        }
Exemple #16
0
        /// <summary>
        /// Translates our CallSignature into a DLR Argument list and gives the simple MetaObject's which are extracted
        /// from the tuple or dictionary parameters being splatted.
        /// </summary>
        private void TranslateArguments(DynamicMetaObject target, DynamicMetaObject /*!*/[] /*!*/ args, out CallInfo /*!*/ callInfo, out List <Expression /*!*/> /*!*/ metaArgs, out Expression test, out BindingRestrictions restrictions)
        {
            Argument[] argInfo = _signature.GetArgumentInfos();

            List <string> namedArgNames = new List <string>();

            metaArgs = new List <Expression>();
            metaArgs.Add(target.Expression);
            Expression splatArgTest   = null;
            Expression splatKwArgTest = null;

            restrictions = BindingRestrictions.Empty;

            for (int i = 0; i < argInfo.Length; i++)
            {
                Argument ai = argInfo[i];

                switch (ai.Kind)
                {
                case ArgumentType.Dictionary:
                    PythonDictionary iac      = (PythonDictionary)args[i].Value;
                    List <string>    argNames = new List <string>();

                    foreach (KeyValuePair <object, object> kvp in iac)
                    {
                        string key = (string)kvp.Key;
                        namedArgNames.Add(key);
                        argNames.Add(key);

                        metaArgs.Add(
                            Expression.Call(
                                AstUtils.Convert(args[i].Expression, typeof(PythonDictionary)),
                                typeof(PythonDictionary).GetMethod("get_Item", new[] { typeof(object) }),
                                AstUtils.Constant(key)
                                )
                            );
                    }

                    restrictions   = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType()));
                    splatKwArgTest = Expression.Call(
                        typeof(PythonOps).GetMethod(nameof(PythonOps.CheckDictionaryMembers)),
                        AstUtils.Convert(args[i].Expression, typeof(PythonDictionary)),
                        AstUtils.Constant(argNames.ToArray())
                        );
                    break;

                case ArgumentType.List:
                    IList <object> splattedArgs = (IList <object>)args[i].Value;
                    splatArgTest = Expression.Equal(
                        Expression.Property(AstUtils.Convert(args[i].Expression, args[i].GetLimitType()), typeof(ICollection <object>).GetProperty("Count")),
                        AstUtils.Constant(splattedArgs.Count)
                        );

                    for (int splattedArg = 0; splattedArg < splattedArgs.Count; splattedArg++)
                    {
                        metaArgs.Add(
                            Expression.Call(
                                AstUtils.Convert(args[i].Expression, typeof(IList <object>)),
                                typeof(IList <object>).GetMethod("get_Item"),
                                AstUtils.Constant(splattedArg)
                                )
                            );
                    }

                    restrictions = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType()));
                    break;

                case ArgumentType.Named:
                    namedArgNames.Add(ai.Name);
                    metaArgs.Add(args[i].Expression);
                    break;

                case ArgumentType.Simple:
                    metaArgs.Add(args[i].Expression);
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }

            callInfo = new CallInfo(metaArgs.Count - 1, namedArgNames.ToArray());

            test = splatArgTest;
            if (splatKwArgTest != null)
            {
                test = test != null?Expression.AndAlso(test, splatKwArgTest) : splatKwArgTest;
            }
        }
        internal static DynamicMetaObject FallbackWorker(PythonContext context, DynamicMetaObject /*!*/ self, DynamicMetaObject /*!*/ codeContext, string name, GetMemberOptions options, DynamicMetaObjectBinder action, DynamicMetaObject errorSuggestion)
        {
            if (self.NeedsDeferral())
            {
                return(action.Defer(self));
            }
            PythonOverloadResolverFactory resolverFactory = new PythonOverloadResolverFactory(context.Binder, codeContext.Expression);

            PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "FallbackGet");

            bool isNoThrow = ((options & GetMemberOptions.IsNoThrow) != 0) ? true : false;
            Type limitType = self.GetLimitType();

            if (limitType == typeof(DynamicNull) || PythonBinder.IsPythonType(limitType))
            {
                // look up in the PythonType so that we can
                // get our custom method names (e.g. string.startswith)
                PythonType argType = DynamicHelpers.GetPythonTypeFromType(limitType);

                // if the name is defined in the CLS context but not the normal context then
                // we will hide it.
                if (argType.IsHiddenMember(name))
                {
                    DynamicMetaObject baseRes = PythonContext.GetPythonContext(action).Binder.GetMember(
                        name,
                        self,
                        resolverFactory,
                        isNoThrow,
                        errorSuggestion
                        );
                    Expression failure = GetFailureExpression(limitType, self, name, isNoThrow, action);

                    return(BindingHelpers.FilterShowCls(codeContext, action, baseRes, failure));
                }
            }

            if (self.GetLimitType() == typeof(OldInstance))
            {
                if ((options & GetMemberOptions.IsNoThrow) != 0)
                {
                    return(new DynamicMetaObject(
                               Ast.Field(
                                   null,
                                   typeof(OperationFailed).GetField("Value")
                                   ),
                               self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance)))
                               ));
                }
                else
                {
                    return(new DynamicMetaObject(
                               Ast.Throw(
                                   Ast.Call(
                                       typeof(PythonOps).GetMethod("AttributeError"),
                                       AstUtils.Constant("{0} instance has no attribute '{1}'"),
                                       Ast.NewArrayInit(
                                           typeof(object),
                                           AstUtils.Constant(((OldInstance)self.Value)._class._name),
                                           AstUtils.Constant(name)
                                           )
                                       )
                                   ),
                               self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance)))
                               ));
                }
            }

            var res = PythonContext.GetPythonContext(action).Binder.GetMember(name, self, resolverFactory, isNoThrow, errorSuggestion);

            // Default binder can return something typed to boolean or int.
            // If that happens, we need to apply Python's boxing rules.
            if (res.Expression.Type.IsValueType)
            {
                res = new DynamicMetaObject(
                    AstUtils.Convert(res.Expression, typeof(object)),
                    res.Restrictions
                    );
            }

            return(res);
        }