示例#1
0
 internal static MethodCallExpression MakeTryGetTypeMember(PythonContext/*!*/ PythonContext, PythonTypeSlot dts, ParameterExpression tmp, Expression instance, Expression pythonType) {
     return Ast.Call(
         PythonTypeInfo._PythonOps.SlotTryGetBoundValue,
         AstUtils.Constant(PythonContext.SharedContext),
         AstUtils.Convert(Utils.WeakConstant(dts), typeof(PythonTypeSlot)),
         AstUtils.Convert(instance, typeof(object)),
         AstUtils.Convert(
             pythonType,
             typeof(PythonType)
         ),
         tmp
     );
 }
示例#2
0
 internal static MethodCallExpression MakeTryGetTypeMember(PythonContext/*!*/ PythonContext, PythonTypeSlot dts, Expression self, ParameterExpression tmp) {
     return MakeTryGetTypeMember(
         PythonContext,
         dts, 
         tmp,
         self,
         Ast.Property(
             Ast.Convert(
                 self,
                 typeof(IPythonObject)),
             PythonTypeInfo._IPythonObject.PythonType
         )
     );
 }
 public SlotInitAdapter(PythonTypeSlot/*!*/ slot, ArgumentValues/*!*/ ai, PythonContext/*!*/ state, Expression/*!*/ codeContext)
     : base(ai, state, codeContext) {
     _slot = slot;
 }
        private static bool MakeOneTarget(PythonContext/*!*/ state, SlotOrFunction/*!*/ target, PythonTypeSlot slotTarget, ConditionalBuilder/*!*/ bodyBuilder, bool reverse, DynamicMetaObject/*!*/[]/*!*/ types) {
            if (target == SlotOrFunction.Empty && slotTarget == null) return true;

            if (slotTarget != null) {
                MakeSlotCall(state, types, bodyBuilder, slotTarget, reverse);
                return true;
            } else if (target.MaybeNotImplemented) {
                Debug.Assert(target.ReturnType == typeof(object));

                ParameterExpression tmp = Ast.Variable(typeof(object), "slot");
                bodyBuilder.AddVariable(tmp);

                bodyBuilder.AddCondition(
                    Ast.NotEqual(
                        Ast.Assign(
                            tmp,
                            target.Target.Expression
                        ),
                        Ast.Property(null, typeof(PythonOps).GetProperty("NotImplemented"))
                    ),
                    tmp
                );

                return true;
            } else {
                bodyBuilder.FinishCondition(target.Target.Expression, typeof(object));
                return false;
            }
        }
        private static void GetOperatorMethods(DynamicMetaObject/*!*/[]/*!*/ types, PythonOperationKind oper, PythonContext state, out SlotOrFunction fbinder, out SlotOrFunction rbinder, out PythonTypeSlot fSlot, out PythonTypeSlot rSlot) {
            oper = NormalizeOperator(oper);
            oper &= ~PythonOperationKind.InPlace;

            string op, rop;
            if (!IsReverseOperator(oper)) {
                op = Symbols.OperatorToSymbol(oper);
                rop = Symbols.OperatorToReversedSymbol(oper);
            } else {
                // coming back after coercion, just try reverse operator.
                rop = Symbols.OperatorToSymbol(oper);
                op = Symbols.OperatorToReversedSymbol(oper);
            }

            fSlot = null;
            rSlot = null;
            PythonType fParent, rParent;

            if (oper == PythonOperationKind.Multiply &&
                IsSequence(types[0]) &&
                !PythonOps.IsNonExtensibleNumericType(types[1].GetLimitType())) {
                // class M:
                //      def __rmul__(self, other):
                //          print "CALLED"
                //          return 1
                //
                // print [1,2] * M()
                //
                // in CPython this results in a successful call to __rmul__ on the type ignoring the forward
                // multiplication.  But calling the __mul__ method directly does NOT return NotImplemented like
                // one might expect.  Therefore we explicitly convert the MetaObject argument into an Index
                // for binding purposes.  That allows this to work at multiplication time but not with
                // a direct call to __mul__.

                DynamicMetaObject[] newTypes = new DynamicMetaObject[2];
                newTypes[0] = types[0];
                newTypes[1] = new DynamicMetaObject(
                    Ast.New(
                        typeof(Index).GetConstructor(new Type[] { typeof(object) }),
                        AstUtils.Convert(types[1].Expression, typeof(object))
                    ),
                    BindingRestrictions.Empty
                );
                types = newTypes;
            }

            if (!SlotOrFunction.TryGetBinder(state, types, op, null, out fbinder, out fParent)) {
                foreach (PythonType pt in MetaPythonObject.GetPythonType(types[0]).ResolutionOrder) {
                    if (pt.TryLookupSlot(state.SharedContext, op, out fSlot)) {
                        fParent = pt;
                        break;
                    }
                }
            }

            if (!SlotOrFunction.TryGetBinder(state, types, null, rop, out rbinder, out rParent)) {
                foreach (PythonType pt in MetaPythonObject.GetPythonType(types[1]).ResolutionOrder) {
                    if (pt.TryLookupSlot(state.SharedContext, rop, out rSlot)) {
                        rParent = pt;
                        break;
                    }
                }
            }

            if (fParent != null && (rbinder.Success || rSlot != null) && rParent != fParent && rParent.IsSubclassOf(fParent)) {
                // Python says if x + subx and subx defines __r*__ we should call r*.
                fbinder = SlotOrFunction.Empty;
                fSlot = null;
            }

            if (!fbinder.Success && !rbinder.Success && fSlot == null && rSlot == null) {
                if (op == "__truediv__" || op == "__rtruediv__") {
                    // true div on a type which doesn't support it, go ahead and try normal divide
                    PythonOperationKind newOp = op == "__truediv__" ? PythonOperationKind.Divide : PythonOperationKind.ReverseDivide;

                    GetOperatorMethods(types, newOp, state, out fbinder, out rbinder, out fSlot, out rSlot);
                }
            }
        }
            /// <summary>
            /// Creates a new CallableObject.  If BuiltinFunction is available we'll create a BuiltinCallable otherwise
            /// we create a SlotCallable.
            /// </summary>
            public static Callable MakeCallable(PythonContext/*!*/ binder, PythonIndexType op, BuiltinFunction itemFunc, PythonTypeSlot itemSlot) {
                if (itemFunc != null) {
                    // we'll call a builtin function to produce the rule
                    return new BuiltinCallable(binder, op, itemFunc);
                } else if (itemSlot != null) {
                    // we'll call a PythonTypeSlot to produce the rule
                    return new SlotCallable(binder, op, itemSlot);
                }

                return null;
            }
示例#7
0
                public bool TryGetSlot(string/*!*/ name, out PythonTypeSlot slot) {
                    Debug.Assert(name != null);

                    KeyValuePair<PythonTypeSlot, MemberGroup> kvp;
                    if (Members.TryGetValue(name, out kvp)) {
                        slot = kvp.Key;
                        return true;
                    }

                    slot = null;
                    return false;
                }
示例#8
0
            /// <summary>
            /// Looks up a cached type slot for the specified member and type.  This may return true and return a null slot - that indicates
            /// that a cached result for a member which doesn't exist has been stored.  Otherwise it returns true if a slot is found or
            /// false if it is not.
            /// </summary>
            public bool TryGetCachedSlot(Type/*!*/ type, string/*!*/ name, out PythonTypeSlot slot) {
                Debug.Assert(type != null); Debug.Assert(name != null);

                if (_cachedInfos != null) {
                    lock (_cachedInfos) {
                        SlotCacheInfo slots;
                        if (_cachedInfos.TryGetValue(type, out slots) &&
                            (slots.TryGetSlot(name, out slot) || slots.ResolvedAll)) {
                            return true;
                        }
                    }
                }

                slot = null;
                return false;
            }
示例#9
0
        /// <summary>
        /// Performs .NET member resolution.  This looks the type and any base types
        /// for members.  It also searches for extension members in the type and any base types.
        /// </summary>
        public bool TryResolveSlot(CodeContext/*!*/ context, PythonType/*!*/ type, PythonType/*!*/ owner, SymbolId name, out PythonTypeSlot slot) {
            Debug.Assert(type.IsSystemType);

            string strName = SymbolTable.IdToString(name);
            Type curType = type.UnderlyingSystemType;

            if (!_resolvedMembers.TryGetCachedSlot(curType, strName, out slot)) {
                MemberGroup mg = TypeInfo.GetMemberAll(
                    this,
                    OldGetMemberAction.Make(this, strName),
                    curType,
                    strName);

                slot = PythonTypeOps.GetSlot(mg, SymbolTable.IdToString(name), PrivateBinding);

                _resolvedMembers.CacheSlot(curType, strName, slot, mg);
            }

            if (slot != null && (slot.IsAlwaysVisible || PythonOps.IsClsVisible(context))) {
                return true;
            }

            slot = null;
            return false;
        }
示例#10
0
        private static void MakeSlotAccess(GetBindingInfo/*!*/ info, PythonTypeSlot dts) {
            ReflectedSlotProperty rsp = dts as ReflectedSlotProperty;
            if (rsp != null) {
                // we need to fall back to __getattr__ if the value is not defined, so call it and check the result.
                info.Body.AddCondition(
                    Ast.NotEqual(
                        Ast.Assign(
                            info.Result,
                            Ast.ArrayAccess(
                                Ast.Call(
                                    Ast.Convert(info.Self, typeof(IObjectWithSlots)),
                                    typeof(IObjectWithSlots).GetMethod("GetSlots")
                                ),
                                Ast.Constant(rsp.Index)
                            )
                        ),
                        Ast.Field(null, typeof(Uninitialized).GetField("Instance"))
                    ),
                    info.Result
                );
                return;
            }

            PythonTypeUserDescriptorSlot slot = dts as PythonTypeUserDescriptorSlot;
            if (slot != null && !(slot.Value is PythonTypeSlot)) {
                PythonType slottype = DynamicHelpers.GetPythonType(slot.Value);
                if (slottype.IsSystemType) {
                    // this is a user slot that's known not to be a descriptor
                    // so we can just burn the value in.  For it to change the
                    // slot will need to be replaced reving the type version.
                    info.Body.FinishCondition(
                        AstUtils.Convert(AstUtils.WeakConstant(slot.Value), typeof(object))
                    );
                    return;
                }
            }

            // users can subclass PythonProperty so check the type explicitly 
            // and only in-line the ones we fully understand.
            if (dts.GetType() == typeof(PythonProperty)) {
                // properties are mutable so we generate code to get the value rather
                // than burning it into the rule.
                Expression getter = Ast.Property(
                    Ast.Convert(AstUtils.WeakConstant(dts), typeof(PythonProperty)),
                    "fget"
                );
                ParameterExpression tmpGetter = Ast.Variable(typeof(object), "tmpGet");
                info.Body.AddVariable(tmpGetter);

                info.Body.FinishCondition(
                    Ast.Block(
                        Ast.Assign(tmpGetter, getter),
                        Ast.Condition(
                            Ast.NotEqual(
                                tmpGetter,
                                Ast.Constant(null)
                            ),
                            Ast.Dynamic(
                                new PythonInvokeBinder(
                                    BinderState.GetBinderState(info.Action),
                                    new CallSignature(1)
                                ),
                                typeof(object),
                                Ast.Constant(BinderState.GetBinderState(info.Action).Context),
                                tmpGetter,
                                info.Self
                            ),
                            Ast.Throw(Ast.Call(typeof(PythonOps).GetMethod("UnreadableProperty")), typeof(object))
                        )
                    )
                );
                return;
            }

            Expression tryGet = Ast.Call(
                TypeInfo._PythonOps.SlotTryGetBoundValue,
                Ast.Constant(BinderState.GetBinderState(info.Action).Context),
                Ast.Convert(AstUtils.WeakConstant(dts), typeof(PythonTypeSlot)),
                AstUtils.Convert(info.Self, typeof(object)),
                Ast.Property(
                    Ast.Convert(
                        info.Self,
                        typeof(IPythonObject)),
                    TypeInfo._IPythonObject.PythonType
                ),
                info.Result
            );

            if (dts.GetAlwaysSucceeds) {
                info.Body.FinishCondition(
                    Ast.Block(tryGet, info.Result)
                );
            } else {
                info.Body.AddCondition(
                    tryGet,
                    info.Result
                );
            }
        }
示例#11
0
        /// <summary>
        /// Checks to see if this type has __getattribute__ that overrides all other attribute lookup.
        /// 
        /// This is more complex then it needs to be.  The problem is that when we have a 
        /// mixed new-style/old-style class we have a weird __getattribute__ defined.  When
        /// we always dispatch through rules instead of PythonTypes it should be easy to remove
        /// this.
        /// </summary>
        private static bool TryGetGetAttribute(CodeContext/*!*/ context, PythonType/*!*/ type, out PythonTypeSlot dts) {
            if (type.TryResolveSlot(context, Symbols.GetAttribute, out dts)) {
                BuiltinMethodDescriptor bmd = dts as BuiltinMethodDescriptor;

                if (bmd == null || bmd.DeclaringType != typeof(object) ||
                    bmd.Template.Targets.Count != 1 ||
                    bmd.Template.Targets[0].DeclaringType != typeof(ObjectOps) ||
                    bmd.Template.Targets[0].Name != "__getattribute__") {
                    return dts != null;
                }
            }
            return false;
        }
示例#12
0
 private static DynamicMetaObject MakeGetItemIterable(DynamicMetaObject metaUserObject, BinderState state, PythonTypeSlot pts, string method) {
     ParameterExpression tmp = Ast.Parameter(typeof(object), "getitemVal");
     return new DynamicMetaObject(
         Expression.Block(
             new[] { tmp },
             Expression.Call(
                 typeof(PythonOps).GetMethod(method),
                 Ast.Block(
                     MetaPythonObject.MakeTryGetTypeMember(
                         state,
                         pts,
                         tmp,
                         metaUserObject.Expression,
                         Ast.Call(
                             typeof(DynamicHelpers).GetMethod("GetPythonType"),
                             AstUtils.Convert(
                                 metaUserObject.Expression,
                                 typeof(object)
                             )
                         )
                     ),
                     tmp
                 ),
                 AstUtils.Constant(
                     CallSite<Func<CallSite, CodeContext, object, int, object>>.Create(
                         new PythonInvokeBinder(state, new CallSignature(1))
                     )
                 )
             )
         ),
         metaUserObject.Restrictions
     );
 }
        public CustomAttributeTracker(Type/*!*/ declaringType, string/*!*/ name, PythonTypeSlot/*!*/ slot) {
            Debug.Assert(slot != null);
            Debug.Assert(declaringType != null);
            Debug.Assert(name != null);

            _declType = declaringType;
            _name = name;
            _slot = slot;
        }
示例#14
0
        public static object GetAttributeNoThrow(CodeContext/*!*/ context, object self, string name, PythonTypeSlot getAttributeSlot, PythonTypeSlot getAttrSlot, SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, string, object>>>/*!*/ callSite) {
            object value;
            if (callSite.Data == null) {
                callSite.Data = MakeGetAttrSite(context);
            }

            try {
                if (getAttributeSlot.TryGetBoundValue(context, self, ((IPythonObject)self).PythonType, out value)) {
                    return callSite.Data.Target(callSite.Data, context, value, name);
                }
            } catch (MissingMemberException) {
                try {
                    if (getAttrSlot != null && getAttrSlot.TryGetBoundValue(context, self, ((IPythonObject)self).PythonType, out value)) {
                        return callSite.Data.Target(callSite.Data, context, value, name);
                    }

                    return OperationFailed.Value;
                } catch (MissingMemberException) {
                    return OperationFailed.Value;
                }
            }

            try {
                if (getAttrSlot != null && getAttrSlot.TryGetBoundValue(context, self, ((IPythonObject)self).PythonType, out value)) {
                    return callSite.Data.Target(callSite.Data, context, value, name);
                }
            } catch (MissingMemberException) {
            }

            return OperationFailed.Value;
        }
示例#15
0
        /// <summary>
        /// Performs .NET member resolution.  This looks within the given type and also
        /// includes any extension members.  Base classes and their extension members are 
        /// not searched.
        /// </summary>
        public bool TryLookupSlot(CodeContext/*!*/ context, PythonType/*!*/ type, SymbolId name, out PythonTypeSlot slot) {
            Debug.Assert(type.IsSystemType);

            return TryLookupProtectedSlot(context, type, name, out slot);
        }
示例#16
0
        /// <summary>
        /// Makes a rule which calls a user-defined __getattribute__ function and falls back to __getattr__ if that
        /// raises an AttributeError.
        /// 
        /// slot is the __getattribute__ method to be called.
        /// </summary>
        private DynamicMetaObject/*!*/ MakeGetAttributeRule(GetBindingInfo/*!*/ info, IPythonObject/*!*/ obj, PythonTypeSlot/*!*/ slot, Expression codeContext) {
            // if the type implements IDynamicObject and we picked up it's __getattribute__ then we want to just 
            // dispatch to the base meta object (or to the default binder). an example of this is:
            //
            // class mc(type):
            //     def __getattr__(self, name):
            //          return 42
            //
            // class nc_ga(object):
            //     __metaclass__ = mc
            //
            // a = nc_ga.x # here we want to dispatch to the type's rule, not call __getattribute__ directly.

            CodeContext context = BinderState.GetBinderState(info.Action).Context;
            Type finalType = PythonTypeOps.GetFinalSystemType(obj.PythonType.UnderlyingSystemType);
            if (typeof(IDynamicObject).IsAssignableFrom(finalType)) {
                PythonTypeSlot baseSlot;
                if (TryGetGetAttribute(context, DynamicHelpers.GetPythonTypeFromType(finalType), out baseSlot) && baseSlot == slot) {
                    return Fallback(info.Action, codeContext);
                }
            }
            
            // otherwise generate code into a helper function.  This will do the slot lookup and exception
            // handling for both __getattribute__ as well as __getattr__ if it exists.
            PythonTypeSlot getattr;
            obj.PythonType.TryResolveSlot(context, Symbols.GetBoundAttr, out getattr);
            DynamicMetaObject self = Restrict(Value.GetType());
            string methodName = BindingHelpers.IsNoThrow(info.Action) ? "GetAttributeNoThrow" : "GetAttribute";
            
            return BindingHelpers.AddDynamicTestAndDefer(
                info.Action,
                new DynamicMetaObject(
                    Ast.Call(
                        typeof(UserTypeOps).GetMethod(methodName),
                        Ast.Constant(BinderState.GetBinderState(info.Action).Context),
                        info.Args[0].Expression,
                        Ast.Constant(GetGetMemberName(info.Action)),
                        Ast.Constant(slot, typeof(PythonTypeSlot)),
                        Ast.Constant(getattr, typeof(PythonTypeSlot)),
                        Ast.Constant(new SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, string, object>>>())
                    ),
                    self.Restrictions
                ),
                info.Args,
                info.Validation
            );
        }
示例#17
0
        /// <summary>
        /// Performs .NET member resolution.  This looks within the given type and also
        /// includes any extension members.  Base classes and their extension members are 
        /// not searched.
        /// 
        /// This version allows PythonType's for protected member resolution.  It shouldn't
        /// be called externally for other purposes.
        /// </summary>
        internal bool TryLookupProtectedSlot(CodeContext/*!*/ context, PythonType/*!*/ type, SymbolId name, out PythonTypeSlot slot) {
            string strName = SymbolTable.IdToString(name);
            Type curType = type.UnderlyingSystemType;

            if (!_typeMembers.TryGetCachedSlot(curType, strName, out slot)) {
                MemberGroup mg = TypeInfo.GetMember(
                    this,
                    OldGetMemberAction.Make(this, name),
                    curType,
                    strName);

                slot = PythonTypeOps.GetSlot(mg, SymbolTable.IdToString(name), PrivateBinding);

                _typeMembers.CacheSlot(curType, strName, slot, mg);
            }

            if (slot != null && (slot.IsAlwaysVisible || PythonOps.IsClsVisible(context))) {
                return true;
            }

            slot = null;
            return false;
        }
示例#18
0
 private static Expression/*!*/ GetWeakSlot(PythonTypeSlot slot) {
     return AstUtils.Convert(AstUtils.WeakConstant(slot), typeof(PythonTypeSlot));
 }
示例#19
0
            /// <summary>
            /// Writes to a cache the result of a type lookup.  Null values are allowed for the slots and they indicate that
            /// the value does not exist.
            /// </summary>
            public void CacheSlot(Type/*!*/ type, string/*!*/ name, PythonTypeSlot slot, MemberGroup/*!*/ memberGroup) {
                Debug.Assert(type != null); Debug.Assert(name != null);

                EnsureInfo();

                lock (_cachedInfos) {
                    SlotCacheInfo slots = GetSlotForType(type);

                    if (slots.ResolvedAll && slot == null && memberGroup.Count == 0) {
                        // nothing to cache, and we know we don't need to cache non-hits.
                        return;
                    }

                    slots.Members[name] = new KeyValuePair<PythonTypeSlot, MemberGroup>(slot, memberGroup);
                }
            }
示例#20
0
 private static bool IsStandardObjectMethod(PythonTypeSlot dts) {
     BuiltinMethodDescriptor bmd = dts as BuiltinMethodDescriptor;
     if (bmd == null) return false;
     return bmd.Template.Targets[0].DeclaringType == typeof(ObjectOps);
 }
示例#21
0
                public void Add(string/*!*/ name, PythonTypeSlot slot, MemberGroup/*!*/ group) {
                    Debug.Assert(name != null); Debug.Assert(group != null);

                    Members[name] = new KeyValuePair<PythonTypeSlot, MemberGroup>(slot, group);
                }
示例#22
0
        private void MakeSetAttrTarget(SetBindingInfo bindingInfo, IPythonObject sdo, PythonTypeSlot dts) {
            ParameterExpression tmp = Ast.Variable(typeof(object), "boundVal");
            bindingInfo.Body.AddVariable(tmp);

            bindingInfo.Body.AddCondition(
                Ast.Call(
                    typeof(PythonOps).GetMethod("SlotTryGetValue"),
                    Ast.Constant(BinderState.GetBinderState(bindingInfo.Action).Context),
                    AstUtils.Convert(AstUtils.WeakConstant(dts), typeof(PythonTypeSlot)),
                    AstUtils.Convert(bindingInfo.Args[0].Expression, typeof(object)),
                    AstUtils.Convert(AstUtils.WeakConstant(sdo.PythonType), typeof(PythonType)),
                    tmp
                ),
                Ast.Dynamic(
                    new PythonInvokeBinder(
                        BinderState.GetBinderState(bindingInfo.Action),
                        new CallSignature(2)
                    ),
                    typeof(object),
                    BinderState.GetCodeContext(bindingInfo.Action),
                    tmp,
                    Ast.Constant(bindingInfo.Action.Name),
                    bindingInfo.Args[1].Expression
                )
            );

            bindingInfo.Body.FinishCondition(
                FallbackSetError(bindingInfo.Action, bindingInfo.Args[1]).Expression
            );
        }
        private static void MakeSlotCallWorker(PythonContext/*!*/ state, PythonTypeSlot/*!*/ slotTarget, Expression/*!*/ self, ConditionalBuilder/*!*/ bodyBuilder, params Expression/*!*/[]/*!*/ args) {
            // Generate:
            // 
            // SlotTryGetValue(context, slot, selfType, out callable) && (tmp=callable(args)) != NotImplemented) ?
            //      tmp :
            //      RestOfOperation
            //
            ParameterExpression callable = Ast.Variable(typeof(object), "slot");
            ParameterExpression tmp = Ast.Variable(typeof(object), "slot");

            bodyBuilder.AddCondition(
                Ast.AndAlso(
                    Ast.Call(
                        typeof(PythonOps).GetMethod("SlotTryGetValue"),
                        AstUtils.Constant(state.SharedContext),
                        AstUtils.Convert(Utils.WeakConstant(slotTarget), typeof(PythonTypeSlot)),
                        AstUtils.Convert(self, typeof(object)),
                        Ast.Call(
                            typeof(DynamicHelpers).GetMethod("GetPythonType"),
                            AstUtils.Convert(self, typeof(object))
                        ),
                        callable
                    ),
                    Ast.NotEqual(
                        Ast.Assign(
                            tmp,
                            DynamicExpression.Dynamic(
                                state.Invoke(
                                    new CallSignature(args.Length)
                                ),
                                typeof(object),
                                ArrayUtils.Insert(AstUtils.Constant(state.SharedContext), (Expression)callable, args)
                            )
                        ),
                        Ast.Property(null, typeof(PythonOps).GetProperty("NotImplemented"))
                    )
                ),
                tmp
            );
            bodyBuilder.AddVariable(callable);
            bodyBuilder.AddVariable(tmp);
        }
示例#24
0
        private static DynamicMetaObject MakeSlotDelete(DeleteBindingInfo/*!*/ info, PythonTypeSlot/*!*/ dts) {

            // users can subclass PythonProperty so check the type explicitly 
            // and only in-line the ones we fully understand.
            if (dts.GetType() == typeof(PythonProperty)) {
                // properties are mutable so we generate code to get the value rather
                // than burning it into the rule.
                Expression deleter = Ast.Property(
                    Ast.Convert(AstUtils.WeakConstant(dts), typeof(PythonProperty)),
                    "fdel"
                );
                ParameterExpression tmpDeleter = Ast.Variable(typeof(object), "tmpDel");
                info.Body.AddVariable(tmpDeleter);

                info.Body.FinishCondition(
                    Ast.Block(
                        Ast.Assign(tmpDeleter, deleter),
                        Ast.Condition(
                            Ast.NotEqual(
                                tmpDeleter,
                                Ast.Constant(null)
                            ),
                            Ast.Dynamic(
                                new PythonInvokeBinder(
                                    BinderState.GetBinderState(info.Action),
                                    new CallSignature(1)
                                ),
                                typeof(void),
                                Ast.Constant(BinderState.GetBinderState(info.Action).Context),
                                tmpDeleter,
                                info.Args[0].Expression
                            ),
                            Ast.Throw(Ast.Call(typeof(PythonOps).GetMethod("UndeletableProperty")))
                        )
                    )
                );
                return info.Body.GetMetaObject();
            }

            info.Body.AddCondition(
                Ast.Call(
                    typeof(PythonOps).GetMethod("SlotTryDeleteValue"),
                    Ast.Constant(BinderState.GetBinderState(info.Action).Context),
                    AstUtils.Convert(AstUtils.WeakConstant(dts), typeof(PythonTypeSlot)),
                    AstUtils.Convert(info.Args[0].Expression, typeof(object)),
                    Ast.Convert(
                        Ast.Property(
                            Ast.Convert(
                                info.Args[0].Expression,
                                typeof(IPythonObject)),
                            TypeInfo._IPythonObject.PythonType
                        ),
                        typeof(PythonType)
                    )
                ),
                Ast.Constant(null)
            );
            return null;
        }
 public SlotCallable(PythonContext/*!*/ binder, PythonIndexType op, PythonTypeSlot slot)
     : base(binder, op) {
     _slot = slot;
 }
示例#26
0
        private static void MakeDeleteAttrTarget(DeleteBindingInfo/*!*/ info, IPythonObject self, PythonTypeSlot dts) {
            ParameterExpression tmp = Ast.Variable(typeof(object), "boundVal");
            info.Body.AddVariable(tmp);

            // call __delattr__
            info.Body.AddCondition(
                Ast.Call(
                    TypeInfo._PythonOps.SlotTryGetBoundValue,
                    Ast.Constant(BinderState.GetBinderState(info.Action).Context),
                    AstUtils.Convert(AstUtils.WeakConstant(dts), typeof(PythonTypeSlot)),
                    AstUtils.Convert(info.Args[0].Expression, typeof(object)),
                    AstUtils.Convert(AstUtils.WeakConstant(self.PythonType), typeof(PythonType)),
                    tmp
                ),
                Ast.Dynamic(
                    new PythonInvokeBinder(
                        BinderState.GetBinderState(info.Action),
                        new CallSignature(1)
                    ),
                    typeof(object),
                    BinderState.GetCodeContext(info.Action),
                    tmp,
                    Ast.Constant(info.Action.Name)
                )
            );
        }
        private static DynamicMetaObject/*!*/ MakeBinaryOperatorResult(DynamicMetaObject/*!*/[]/*!*/ types, DynamicMetaObjectBinder/*!*/ operation, PythonOperationKind op, SlotOrFunction/*!*/ fCand, SlotOrFunction/*!*/ rCand, PythonTypeSlot fSlot, PythonTypeSlot rSlot, DynamicMetaObject errorSuggestion) {
            Assert.NotNull(operation, fCand, rCand);

            SlotOrFunction fTarget, rTarget;
            PythonContext state = PythonContext.GetPythonContext(operation);

            ConditionalBuilder bodyBuilder = new ConditionalBuilder(operation);

            if ((op & PythonOperationKind.InPlace) != 0) {
                // in place operator, see if there's a specific method that handles it.
                SlotOrFunction function = SlotOrFunction.GetSlotOrFunction(PythonContext.GetPythonContext(operation), Symbols.OperatorToSymbol(op), types);

                // we don't do a coerce for in place operators if the lhs implements __iop__
                if (!MakeOneCompareGeneric(function, false, types, MakeCompareReturn, bodyBuilder, typeof(object))) {
                    // the method handles it and always returns a useful value.
                    return bodyBuilder.GetMetaObject(types);
                }
            }

            if (!SlotOrFunction.GetCombinedTargets(fCand, rCand, out fTarget, out rTarget) &&
                fSlot == null &&
                rSlot == null &&
                !ShouldCoerce(state, op, types[0], types[1], false) &&
                !ShouldCoerce(state, op, types[1], types[0], false) &&
                bodyBuilder.NoConditions) {
                return MakeRuleForNoMatch(operation, op, errorSuggestion, types);
            }

            if (ShouldCoerce(state, op, types[0], types[1], false) &&
                (op != PythonOperationKind.Mod || !MetaPythonObject.GetPythonType(types[0]).IsSubclassOf(TypeCache.String))) {
                // need to try __coerce__ first.
                DoCoerce(state, bodyBuilder, op, types, false);
            }

            if (MakeOneTarget(PythonContext.GetPythonContext(operation), fTarget, fSlot, bodyBuilder, false, types)) {
                if (ShouldCoerce(state, op, types[1], types[0], false)) {
                    // need to try __coerce__ on the reverse first                    
                    DoCoerce(state, bodyBuilder, op, new DynamicMetaObject[] { types[1], types[0] }, true);
                }

                if (rSlot != null) {
                    MakeSlotCall(PythonContext.GetPythonContext(operation), types, bodyBuilder, rSlot, true);
                    bodyBuilder.FinishCondition(MakeBinaryThrow(operation, op, types).Expression, typeof(object));
                } else if (MakeOneTarget(PythonContext.GetPythonContext(operation), rTarget, rSlot, bodyBuilder, false, types)) {
                    // need to fallback to throwing or coercion
                    bodyBuilder.FinishCondition(MakeBinaryThrow(operation, op, types).Expression, typeof(object));
                }
            }

            return bodyBuilder.GetMetaObject(types);
        }
示例#28
0
 public SlotOrFunction(DynamicMetaObject/*!*/ target, PythonTypeSlot slot) {
     _target = target;
     _slot = slot;
 }
        private static void MakeSlotCall(PythonContext/*!*/ state, DynamicMetaObject/*!*/[]/*!*/ types, ConditionalBuilder/*!*/ bodyBuilder, PythonTypeSlot/*!*/ slotTarget, bool reverse) {
            Debug.Assert(slotTarget != null);

            Expression self, other;
            if (reverse) {
                self = types[1].Expression;
                other = types[0].Expression;
            } else {
                self = types[0].Expression;
                other = types[1].Expression;
            }

            MakeSlotCallWorker(state, slotTarget, self, bodyBuilder, other);
        }
        private NewAdapter/*!*/ GetNewAdapter(ArgumentValues/*!*/ ai, PythonTypeSlot/*!*/ newInst, DynamicMetaObjectBinder/*!*/ call, Expression/*!*/ codeContext) {
            PythonContext state = PythonContext.GetPythonContext(call);

            if (Value.IsMixedNewStyleOldStyle()) {
                return new MixedNewAdapter(ai, state, codeContext);
            } else if (newInst == InstanceOps.New) {
                return new DefaultNewAdapter(ai, Value, state, codeContext);
            } else if (newInst is ConstructorFunction) {
                return new ConstructorNewAdapter(ai, Value, state, codeContext);
            } else if (newInst is BuiltinFunction) {
                return new BuiltinNewAdapter(ai, Value, ((BuiltinFunction)newInst), state, codeContext);
            }

            return new NewAdapter(ai, state, codeContext);
        }