Exemplo n.º 1
0
        private Expression/*!*/ MaybeMakeNoThrow(GetBindingInfo/*!*/ info, Expression/*!*/ expr, Expression codeContext) {
            if (BindingHelpers.IsNoThrow(info.Action)) {
                DynamicMetaObject fallback = FallbackGetError(info.Action, codeContext);
                Type t = BindingHelpers.GetCompatibleType(expr.Type, fallback.Expression.Type);
                ParameterExpression tmp = Ast.Variable(t, "getAttrRes");

                expr = Ast.Block(
                    new ParameterExpression[] { tmp },
                    Ast.Block(
                        AstUtils.Try(
                            Ast.Assign(tmp, AstUtils.Convert(expr, t))
                        ).Catch(
                            typeof(MissingMemberException),
                            Ast.Assign(tmp, AstUtils.Convert(FallbackGetError(info.Action, codeContext).Expression, t))
                        ),
                        tmp
                    )
                );
            }
            return expr;
        }
Exemplo n.º 2
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
            );
        }
Exemplo n.º 3
0
 private static MethodCallExpression/*!*/ MakeGetAttrTestAndGet(GetBindingInfo/*!*/ info, Expression/*!*/ getattr) {
     return Ast.Call(
         TypeInfo._PythonOps.SlotTryGetBoundValue,
         Ast.Constant(BinderState.GetBinderState(info.Action).Context),
         AstUtils.Convert(getattr, typeof(PythonTypeSlot)),
         AstUtils.Convert(info.Self, typeof(object)),
         Ast.Convert(
             Ast.Property(
                 Ast.Convert(
                     info.Self,
                     typeof(IPythonObject)),
                 TypeInfo._IPythonObject.PythonType
             ),
             typeof(PythonType)
         ),
         info.Result
     );
 }
Exemplo n.º 4
0
        private Expression/*!*/ MakeGetAttrCall(GetBindingInfo/*!*/ info, Expression codeContext) {
            Expression call = Ast.Dynamic(
                new PythonInvokeBinder(
                    BinderState.GetBinderState(info.Action),
                    new CallSignature(1)
                ),
                typeof(object),
                BinderState.GetCodeContext(info.Action),
                info.Result,
                Ast.Constant(GetGetMemberName(info.Action))
            );

            call = MaybeMakeNoThrow(info, call, codeContext);

            return call;
        }
Exemplo n.º 5
0
 private void MakeGetAttrRule(GetBindingInfo/*!*/ info, Expression/*!*/ getattr, Expression codeContext) {
     info.Body.AddCondition(
         MakeGetAttrTestAndGet(info, getattr),
         MakeGetAttrCall(info, codeContext)
     );
 }
Exemplo n.º 6
0
 /// <summary>
 /// Checks a range of the MRO to perform old-style class lookups if any old-style classes
 /// are present.  We will call this twice to produce a search before a slot and after
 /// a slot.
 /// </summary>
 private void MakeOldStyleAccess(GetBindingInfo/*!*/ info) {
     info.Body.AddCondition(
         Ast.Call(
             typeof(UserTypeOps).GetMethod("TryGetMixedNewStyleOldStyleSlot"),
             Ast.Constant(BinderState.GetBinderState(info.Action).Context),
             AstUtils.Convert(info.Self, typeof(object)),
             AstUtils.Constant(SymbolTable.StringToId(GetGetMemberName(info.Action))),
             info.Result
         ),
         info.Result
     );
 }
Exemplo n.º 7
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
                );
            }
        }
Exemplo n.º 8
0
 private void MakeDictionaryAccess(GetBindingInfo/*!*/ info) {
     info.Body.AddCondition(
         Ast.AndAlso(
             Ast.NotEqual(
                 Ast.Property(
                     Ast.Convert(info.Self, typeof(IPythonObject)),
                     TypeInfo._IPythonObject.Dict
                 ),
                 Ast.Constant(null)
             ),
             Ast.Call(
                 Ast.Property(
                     Ast.Convert(info.Self, typeof(IPythonObject)),
                     TypeInfo._IPythonObject.Dict
                 ),
                 TypeInfo._IAttributesCollection.TryGetvalue,
                 AstUtils.Constant(SymbolTable.StringToId(GetGetMemberName(info.Action))),
                 info.Result
             )
         ),
         info.Result
     );
 }
Exemplo n.º 9
0
        private DynamicMetaObject GetMemberWorker(DynamicMetaObjectBinder/*!*/ member, Expression codeContext) {
            DynamicMetaObject self = Restrict(Value.GetType());
            CodeContext context = BinderState.GetBinderState(member).Context;
            IPythonObject sdo = Value;
            GetBindingInfo bindingInfo = new GetBindingInfo(
                member,
                new DynamicMetaObject[] { this },
                Ast.Variable(Expression.Type, "self"),
                Ast.Variable(typeof(object), "lookupRes"),
                new ConditionalBuilder(member),
                BindingHelpers.GetValidationInfo(self.Expression, sdo.PythonType)
            );

            PythonTypeSlot foundSlot;
            if (TryGetGetAttribute(context, sdo.PythonType, out foundSlot)) {
                return MakeGetAttributeRule(bindingInfo, sdo, foundSlot, codeContext);
            }

            // otherwise look the object according to Python rules:
            //  1. 1st search the MRO of the type, and if it's there, and it's a get/set descriptor,
            //      return that value.
            //  2. Look in the instance dictionary.  If it's there return that value, otherwise return
            //      a value found during the MRO search.  If no value was found during the MRO search then
            //      raise an exception.      
            //  3. fall back to __getattr__ if defined.
            //
            // Ultimately we cache the result of the MRO search based upon the type version.  If we have
            // a get/set descriptor we'll only ever use that directly.  Otherwise if we have a get descriptor
            // we'll first check the dictionary and then invoke the get descriptor.  If we have no descriptor
            // at all we'll just check the dictionary.  If both lookups fail we'll raise an exception.

            bool isOldStyle;
            bool systemTypeResolution;
            foundSlot = FindSlot(context, GetGetMemberName(member), sdo, out isOldStyle, out systemTypeResolution);

            if (!isOldStyle || foundSlot is ReflectedSlotProperty) {
                if (sdo.HasDictionary && (foundSlot == null || !foundSlot.IsSetDescriptor(context, sdo.PythonType))) {
                    MakeDictionaryAccess(bindingInfo);
                }

                if (foundSlot != null) {
                    if (systemTypeResolution) {
                        bindingInfo.Body.FinishCondition(GetMemberFallback(member, codeContext).Expression);
                    } else {
                        MakeSlotAccess(bindingInfo, foundSlot);
                    }
                }
            } else {
                MakeOldStyleAccess(bindingInfo);
            }

            if (!bindingInfo.Body.IsFinal) {
                // fall back to __getattr__ if it's defined.
                PythonTypeSlot getattr;
                if (sdo.PythonType.TryResolveSlot(context, Symbols.GetBoundAttr, out getattr)) {
                    MakeGetAttrRule(bindingInfo, GetWeakSlot(getattr), codeContext);
                }

                bindingInfo.Body.FinishCondition(FallbackGetError(member, null).Expression);
            }

            DynamicMetaObject res = bindingInfo.Body.GetMetaObject(this);
            res = new DynamicMetaObject(
                Ast.Block(
                    new ParameterExpression[] { bindingInfo.Self, bindingInfo.Result },
                    Ast.Assign(bindingInfo.Self, self.Expression),
                    res.Expression
                ),
                self.Restrictions.Merge(res.Restrictions)
            );

            return BindingHelpers.AddDynamicTestAndDefer(
                member,
                res,
                new DynamicMetaObject[] { this },
                bindingInfo.Validation
            );
        }