Example #1
0
        internal static DynamicMetaObject Call(DynamicMetaObjectBinder call, DynamicMetaObject target, DynamicMetaObject[] args)
        {
            Assert.NotNull(call, args);
            Assert.NotNullItems(args);

            if (target.NeedsDeferral())
                return call.Defer(ArrayUtils.Insert(target, args));

            foreach (var mo in args)
            {
                if (mo.NeedsDeferral())
                {
                    RestrictTypes(args);

                    return call.Defer(
                        ArrayUtils.Insert(target, args)
                    );
                }
            }

            DynamicMetaObject self = target.Restrict(target.GetLimitType());

            ValidationInfo valInfo = BindingHelpers.GetValidationInfo(target);
            TotemType tt = DynamicHelpers.GetTotemType(target.Value);
            TotemContext toContext = GetTotemContext(call);

            throw new NotImplementedException();
        }
        public DynamicMetaObject DeleteMember(string name, DynamicMetaObject target, Expression codeContext) {
            ContractUtils.RequiresNotNull(name, "name");
            ContractUtils.RequiresNotNull(target, "target");

            return MakeDeleteMemberTarget(
                new SetOrDeleteMemberInfo(
                    name,
                    codeContext
                ),
                target.Restrict(target.GetLimitType())
            );
        }
        public DynamicMetaObject DeleteMember(string name, DynamicMetaObject target, OverloadResolverFactory resolutionFactory) {
            ContractUtils.RequiresNotNull(name, "name");
            ContractUtils.RequiresNotNull(target, "target");

            return MakeDeleteMemberTarget(
                new SetOrDeleteMemberInfo(
                    name,
                    resolutionFactory
                ),
                target.Restrict(target.GetLimitType())
            );
        }
        private DynamicMetaObject MakeSetMemberTarget(SetOrDeleteMemberInfo memInfo, DynamicMetaObject target, DynamicMetaObject value) {
            Type type = target.GetLimitType();
            Expression self = target.Expression;
            
            target = target.Restrict(target.GetLimitType());

            memInfo.Body.Restrictions = target.Restrictions;

            if (typeof(TypeTracker).IsAssignableFrom(type)) {
                type = ((TypeTracker)target.Value).Type;
                self = null;

                memInfo.Body.Restrictions = memInfo.Body.Restrictions.Merge(
                    BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value)
                );
            }

            MakeSetMemberRule(memInfo, type, self, value);

            return memInfo.Body.GetMetaObject(target, value);
        }
        protected static DynamicMetaObject GetMemberFallback(DynamicMetaObject self, DynamicMetaObjectBinder member, DynamicMetaObject codeContext) {
            PythonGetMemberBinder gmb = member as PythonGetMemberBinder;
            if (gmb != null) {
                return gmb.Fallback(self, codeContext);
            }

            GetMemberBinder gma = (GetMemberBinder)member;

            return gma.FallbackGetMember(self.Restrict(self.GetLimitType()));
        }
        private DynamicMetaObject MakeGetMemberTarget(GetMemberInfo getMemInfo, DynamicMetaObject target) {
            Type type = target.GetLimitType();
            BindingRestrictions restrictions = target.Restrictions;
            Expression self = target.Expression;
            target = target.Restrict(target.GetLimitType());

            // needed for GetMember call until DynamicAction goes away
            OldDynamicAction act = OldGetMemberAction.Make(
                this,
                getMemInfo.Name
            );

            // Specially recognized types: TypeTracker, NamespaceTracker, and StrongBox.  
            // TODO: TypeTracker and NamespaceTracker should technically be IDO's.
            MemberGroup members = MemberGroup.EmptyGroup;
            if (typeof(TypeTracker).IsAssignableFrom(type)) {
                restrictions = restrictions.Merge(
                    BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value)
                );

                TypeGroup tg = target.Value as TypeGroup;
                Type nonGen;
                if (tg == null || tg.TryGetNonGenericType(out nonGen)) {
                    members = GetMember(act, ((TypeTracker)target.Value).Type, getMemInfo.Name);
                    if (members.Count > 0) {
                        // we have a member that's on the type associated w/ the tracker, return that...
                        type = ((TypeTracker)target.Value).Type;
                        self = null;
                    }
                }
            }

            if (members.Count == 0) {
                // Get the members
                members = GetMember(act, type, getMemInfo.Name);
            }

            if (members.Count == 0) {
                if (typeof(TypeTracker).IsAssignableFrom(type)) {
                    // ensure we don't have a non-generic type, and if we do report an error now.  This matches
                    // the rule version of the default binder but should probably be removed long term
                    Type x = ((TypeTracker)target.Value).Type;
                } else if (type.IsInterface) {
                    // all interfaces have object members
                    type = typeof(object);
                    members = GetMember(act, type, getMemInfo.Name);
                }
            }

            Expression propSelf = self;
            // if lookup failed try the strong-box type if available.
            if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(type)) {
                // properties/fields need the direct value, methods hold onto the strong box.
                propSelf = Ast.Field(AstUtils.Convert(self, type), type.GetField("Value"));

                type = type.GetGenericArguments()[0];

                members = GetMember(
                    act,
                    type,
                    getMemInfo.Name
                );
            }

            MakeBodyHelper(getMemInfo, self, propSelf, type, members);

            getMemInfo.Body.Restrictions = restrictions;
            return getMemInfo.Body.GetMetaObject(target);
        }
Example #7
0
 private DynamicMetaObject RestrictArgument(DynamicMetaObject arg, ParameterWrapper parameter) {
     if (parameter.Type == typeof(object)) {
         // don't use Restrict as it'll box & unbox.
         return new DynamicMetaObject(arg.Expression, BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg.Expression, arg.GetLimitType()));
     } else {
         return arg.Restrict(arg.GetLimitType());
     }
 }
Example #8
0
        public override DynamicMetaObject FallbackConvert(DynamicMetaObject self, DynamicMetaObject onBindingError) {
            if (self.NeedsDeferral()) {
                return Defer(self);
            }

            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.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<>)) {
                            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 (self.GetLimitType() == typeof(string)) {
                            // replace strings normal enumeration with our own which returns strings instead of chars.
                            res = new DynamicMetaObject(
                                Ast.Call(
                                    typeof(StringOps).GetMethod("ConvertToIEnumerable"),
                                    AstUtils.Convert(self.Expression, typeof(string))
                                ),
                                BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(string))
                            );
                        } else if (!typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self)) {
                            res = PythonProtocol.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 = PythonProtocol.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)),
                            Ast.Constant(Activator.CreateInstance(self.GetLimitType()))
                        ),
                        Ast.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 ?? Binder.Binder.ConvertTo(Type, ResultKind, self);
        }
Example #9
0
        private DynamicMetaObject TryToCharConversion(DynamicMetaObject/*!*/ self) {
            DynamicMetaObject res;
            // we have an implicit conversion to char if the
            // string length == 1, but we can only represent
            // this is implicit via a rule.
            string strVal = self.Value as string;
            Expression strExpr = self.Expression;
            if (strVal == null) {
                Extensible<string> extstr = self.Value as Extensible<string>;
                if (extstr != null) {
                    strVal = extstr.Value;
                    strExpr =
                        Ast.Property(
                            AstUtils.Convert(
                                strExpr,
                                typeof(Extensible<string>)
                            ),
                            typeof(Extensible<string>).GetProperty("Value")
                        );
                }
            }

            // we can only produce a conversion if we have a string value...
            if (strVal != null) {
                self = self.Restrict(self.GetRuntimeType());

                Expression getLen = Ast.Property(
                    AstUtils.Convert(
                        strExpr,
                        typeof(string)
                    ),
                    typeof(string).GetProperty("Length")
                );

                if (strVal.Length == 1) {
                    res = new DynamicMetaObject(
                        Ast.Call(
                            AstUtils.Convert(strExpr, typeof(string)),
                            typeof(string).GetMethod("get_Chars"),
                            Ast.Constant(0)
                        ),
                        self.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Ast.Equal(getLen, Ast.Constant(1))))
                    );
                } else {
                    res = new DynamicMetaObject(
                        Ast.Throw(
                            Ast.Call(
                                typeof(PythonOps).GetMethod("TypeError"),
                                Ast.Constant("expected string of length 1 when converting to char, got '{0}'"),
                                Ast.NewArrayInit(typeof(object), self.Expression)
                            )
                        ),
                        self.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Ast.NotEqual(getLen, Ast.Constant(1))))
                    );
                }
            } else {
                // let the base class produce the rule
                res = null;
            }

            return res;
        }
Example #10
0
        private DynamicMetaObject/*!*/ MakeToArrayConversion(DynamicMetaObject/*!*/ self, Type/*!*/ toType) {
            self = self.Restrict(typeof(PythonTuple));

            return new DynamicMetaObject(
                Ast.Call(
                    typeof(PythonOps).GetMethod("ConvertTupleToArray").MakeGenericMethod(toType.GetElementType()),
                    self.Expression
                ),
                self.Restrictions
            );
        }
Example #11
0
        private DynamicMetaObject TryToGenericInterfaceConversion(DynamicMetaObject/*!*/ self, Type/*!*/ toType, Type/*!*/ fromType, Type/*!*/ wrapperType) {
            if (fromType.IsAssignableFrom(CompilerHelpers.GetType(self.Value))) {
                Type making = wrapperType.MakeGenericType(toType.GetGenericArguments());

                self = self.Restrict(CompilerHelpers.GetType(self.Value));

                return new DynamicMetaObject(
                    Ast.New(
                        making.GetConstructor(new Type[] { fromType }),
                        AstUtils.Convert(
                            self.Expression,
                            fromType
                        )
                    ),
                    self.Restrictions
                );
            }
            return null;
        }
Example #12
0
            public override DynamicMetaObject/*!*/ FallbackSetMember(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/ value,
                DynamicMetaObject errorSuggestion) {

#if !SILVERLIGHT
                DynamicMetaObject result;
                if (Microsoft.Scripting.ComInterop.ComBinder.TryBindSetMember(this, target, ConvertComArgument(value), out result)) {
                    return result;
                }
#endif

                return errorSuggestion ?? new DynamicMetaObject(
                    Expression.Throw(
                        Expression.New(
                            typeof(MissingMemberException).GetConstructor(new[] { typeof(string) }),
                            Expression.Constant(String.Format("unknown member: {0}", Name))
                        ),
                        typeof(object)
                    ),
                    target.Restrict(CompilerHelpers.GetType(target.Value)).Restrictions
                );
            }
Example #13
0
            public override DynamicMetaObject/*!*/ Bind(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args) {
                Debug.Assert(args.Length == 1);

                if (_setMemberUnmangled == null) {
                    // no unmangled name, just do the set member binding
                    return _setMember.Bind(target, args);
                }

                //
                // Consider this case:
                // x = {"Foo" -> 1}.
                // x.foo += 1
                // Without name mangling this would result to x being {"Foo" -> 1, "foo" -> 2} while the expected result is {"Foo" -> 2}.
                //
                // Hence if the object doesn't contain the member but contains an unmangled member we set the unmangled one:
                //
                return new DynamicMetaObject(
                    Expression.Condition(
                        Expression.AndAlso(
                            Expression.Equal(
                                AstUtils.LightDynamic(_tryGetMember, typeof(object), target.Expression),
                                Expression.Constant(OperationFailed.Value)
                            ),
                            Expression.NotEqual(
                                AstUtils.LightDynamic(_tryGetMemberUnmangled, typeof(object), target.Expression),
                                Expression.Constant(OperationFailed.Value)
                            )
                        ),
                        AstUtils.LightDynamic(_setMemberUnmangled, typeof(object), target.Expression, args[0].Expression),
                        AstUtils.LightDynamic(_setMember, typeof(object), target.Expression, args[0].Expression)
                    ),
                    target.Restrict(CompilerHelpers.GetType(target.Value)).Restrictions
                );
            }
Example #14
0
            public override DynamicMetaObject/*!*/ FallbackGetMember(DynamicMetaObject/*!*/ target, DynamicMetaObject errorSuggestion) {
#if !SILVERLIGHT
                DynamicMetaObject result;
                if (Microsoft.Scripting.ComInterop.ComBinder.TryBindGetMember(this, target, out result)) {
                    return result;
                }
#endif

                return new DynamicMetaObject(
                    Expression.Constant(OperationFailed.Value, typeof(object)),
                    target.Restrict(CompilerHelpers.GetType(target.Value)).Restrictions
                );
            }
Example #15
0
        internal static DynamicMetaObject Call(DynamicMetaObjectBinder/*!*/ call, DynamicMetaObject target, DynamicMetaObject/*!*/[]/*!*/ args) {
            Assert.NotNull(call, args);
            Assert.NotNullItems(args);

            if (target.NeedsDeferral()) {
                return call.Defer(ArrayUtils.Insert(target, args));
            }

            foreach (DynamicMetaObject mo in args) {
                if (mo.NeedsDeferral()) {
                    RestrictTypes(args);

                    return call.Defer(
                        ArrayUtils.Insert(target, args)
                    );
                }
            }

            DynamicMetaObject self = target.Restrict(target.GetLimitType());

            ValidationInfo valInfo = BindingHelpers.GetValidationInfo(target);
            PythonType pt = DynamicHelpers.GetPythonType(target.Value);
            BinderState state = BinderState.GetBinderState(call);

            // look for __call__, if it's present dispatch to it.  Otherwise fall back to the
            // default binder
            PythonTypeSlot callSlot;
            if (!typeof(Delegate).IsAssignableFrom(target.GetLimitType()) &&
                pt.TryResolveSlot(state.Context, Symbols.Call, out callSlot)) {
                ConditionalBuilder cb = new ConditionalBuilder(call);
                Expression body;

                callSlot.MakeGetExpression(
                    state.Binder,
                    BinderState.GetCodeContext(call),
                    self.Expression,
                    GetPythonType(self),
                    cb
                );
                
                if (!cb.IsFinal) {
                    cb.FinishCondition(GetCallError(self));
                }

                Expression[] callArgs = ArrayUtils.Insert(
                    BinderState.GetCodeContext(call),
                    cb.GetMetaObject().Expression, 
                    DynamicUtils.GetExpressions(args)
                );

                body = Ast.Dynamic(
                    BinderState.GetBinderState(call).Invoke(
                        BindingHelpers.GetCallSignature(call)
                    ),
                    typeof(object),
                    callArgs
                );

                return BindingHelpers.AddDynamicTestAndDefer(
                    call,
                    new DynamicMetaObject(body, self.Restrictions.Merge(BindingRestrictions.Combine(args))),
                    args,
                    valInfo
                );
            }

            return null;
        }
Example #16
0
        private DynamicMetaObject/*!*/ MakeToBoolConversion(DynamicMetaObject/*!*/ self) {
            DynamicMetaObject res = null;
            if (self.NeedsDeferral()) {
                res = Defer(self);
            } else {
                if (self.HasValue) {
                    self = self.Restrict(self.GetRuntimeType());
                }

                // Optimization: if we already boxed it to a bool, and now
                // we're unboxing it, remove the unnecessary box.
                if (self.Expression.NodeType == ExpressionType.Convert && self.Expression.Type == typeof(object)) {
                    var convert = (UnaryExpression)self.Expression;
                    if (convert.Operand.Type == typeof(bool)) {
                        return new DynamicMetaObject(convert.Operand, self.Restrictions);
                    }
                }

                if (self.GetLimitType() == typeof(DynamicNull)) {
                    // None has no __nonzero__ and no __len__ but it's always false
                    res = MakeNoneToBoolConversion(self);
                } else if (self.GetLimitType() == typeof(bool)) {
                    // nothing special to convert from bool to bool
                    res = self;
                } else if (typeof(IStrongBox).IsAssignableFrom(self.GetLimitType())) {
                    // Explictly block conversion of References to bool
                    res = MakeStrongBoxToBoolConversionError(self);
                } else if (self.GetLimitType().IsPrimitive || self.GetLimitType().IsEnum) {
                    // optimization - rather than doing a method call for primitives and enums generate
                    // the comparison to zero directly.
                    res = MakePrimitiveToBoolComparison(self);
                } else {
                    // anything non-null that doesn't fall under one of the above rules is true.  So we
                    // fallback to the base Python conversion which will check for __nonzero__ and
                    // __len__.  The fallback is handled by our ConvertTo site binder.
                    return
                        PythonProtocol.ConvertToBool(this, self) ??
                        new DynamicMetaObject(
                            Ast.Constant(true),
                            self.Restrictions
                        );
                }
            }

            return res;
        }
Example #17
0
        private DynamicMetaObject MakeGetMemberTarget(GetMemberInfo getMemInfo, DynamicMetaObject target) {
            Type type = target.GetLimitType();
            BindingRestrictions restrictions = target.Restrictions;
            DynamicMetaObject self = target;
            target = target.Restrict(target.GetLimitType());

            // Specially recognized types: TypeTracker, NamespaceTracker, and StrongBox.  
            // TODO: TypeTracker and NamespaceTracker should technically be IDO's.
            MemberGroup members = MemberGroup.EmptyGroup;
            if (typeof(TypeTracker).IsAssignableFrom(type)) {
                restrictions = restrictions.Merge(
                    BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value)
                );

                TypeGroup tg = target.Value as TypeGroup;
                Type nonGen;
                if (tg == null || tg.TryGetNonGenericType(out nonGen)) {
                    members = GetMember(MemberRequestKind.Get, ((TypeTracker)target.Value).Type, getMemInfo.Name);
                    if (members.Count > 0) {
                        // we have a member that's on the type associated w/ the tracker, return that...
                        type = ((TypeTracker)target.Value).Type;
                        self = null;
                    }
                }
            }

            if (members.Count == 0) {
                // Get the members
                members = GetMember(MemberRequestKind.Get, type, getMemInfo.Name);
            }

            if (members.Count == 0) {
                if (type.IsInterface) {
                    // all interfaces have object members
                    type = typeof(object);
                    members = GetMember(MemberRequestKind.Get, type, getMemInfo.Name);
                }
            }

            DynamicMetaObject propSelf = self == null ? null : self;
            // if lookup failed try the strong-box type if available.
            if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(type) && propSelf != null) {
                // properties/fields need the direct value, methods hold onto the strong box.
                propSelf = new DynamicMetaObject(
                    Ast.Field(AstUtils.Convert(propSelf.Expression, type), type.GetField("Value")),
                    propSelf.Restrictions,
                    ((IStrongBox)propSelf.Value).Value
                );

                type = type.GetGenericArguments()[0];

                members = GetMember(
                    MemberRequestKind.Get,
                    type,
                    getMemInfo.Name
                );
            }

            MakeBodyHelper(getMemInfo, self, propSelf, type, members);

            getMemInfo.Body.Restrictions = restrictions;
            return getMemInfo.Body.GetMetaObject(target);
        }