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 ); }
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; }
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; }
/// <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; }
/// <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; }
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 ); } }
/// <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; }
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; }
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; }
/// <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); }
/// <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 ); }
/// <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; }
private static Expression/*!*/ GetWeakSlot(PythonTypeSlot slot) { return AstUtils.Convert(AstUtils.WeakConstant(slot), typeof(PythonTypeSlot)); }
/// <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); } }
private static bool IsStandardObjectMethod(PythonTypeSlot dts) { BuiltinMethodDescriptor bmd = dts as BuiltinMethodDescriptor; if (bmd == null) return false; return bmd.Template.Targets[0].DeclaringType == typeof(ObjectOps); }
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); }
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); }
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; }
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); }
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); }