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(); }
internal static DynamicMetaObject FallbackWorker(DynamicMetaObject/*!*/ self, Expression/*!*/ codeContext, string name, GetMemberOptions options, DynamicMetaObjectBinder action) { if (self.NeedsDeferral()) { return action.Defer(self); } bool isNoThrow = ((options & GetMemberOptions.IsNoThrow) != 0) ? true : false; Type limitType = self.GetLimitType() ; if (limitType == typeof(DynamicNull) || PythonBinder.IsPythonType(limitType)) { // look up in the PythonType so that we can // get our custom method names (e.g. string.startswith) PythonType argType = DynamicHelpers.GetPythonTypeFromType(limitType); // if the name is defined in the CLS context but not the normal context then // we will hide it. if (argType.IsHiddenMember(name)) { DynamicMetaObject baseRes = BinderState.GetBinderState(action).Binder.GetMember( name, self, codeContext, isNoThrow ); Expression failure = GetFailureExpression(limitType, name, isNoThrow, action); return BindingHelpers.FilterShowCls(codeContext, action, baseRes, failure); } } if (self.GetLimitType() == typeof(OldInstance)) { if ((options & GetMemberOptions.IsNoThrow) != 0) { return new DynamicMetaObject( Ast.Field( null, typeof(OperationFailed).GetField("Value") ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance))) ); } else { return new DynamicMetaObject( Ast.Throw( Ast.Call( typeof(PythonOps).GetMethod("AttributeError"), Ast.Constant("{0} instance has no attribute '{1}'"), Ast.NewArrayInit( typeof(object), Ast.Constant(((OldInstance)self.Value)._class._name), Ast.Constant(name) ) ) ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance))) ); } } var res = BinderState.GetBinderState(action).Binder.GetMember(name, self, codeContext, isNoThrow); // Default binder can return something typed to boolean or int. // If that happens, we need to apply Python's boxing rules. if (res.Expression.Type == typeof(bool) || res.Expression.Type == typeof(int)) { res = new DynamicMetaObject( AstUtils.Convert(res.Expression, typeof(object)), res.Restrictions ); } return res; }
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; }
/// <summary> /// Transforms an invoke member into a Python GetMember/Invoke. The caller should /// verify that the given attribute is not resolved against a normal .NET class /// before calling this. If it is a normal .NET member then a fallback InvokeMember /// is preferred. /// </summary> internal static DynamicMetaObject/*!*/ GenericInvokeMember(InvokeMemberBinder/*!*/ action, ValidationInfo valInfo, DynamicMetaObject target, DynamicMetaObject/*!*/[]/*!*/ args) { if (target.NeedsDeferral()) { return action.Defer(args); } return AddDynamicTestAndDefer(action, action.FallbackInvoke( new DynamicMetaObject( Binders.Get( PythonContext.GetCodeContext(action), PythonContext.GetPythonContext(action), typeof(object), action.Name, target.Expression ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target) ), args, null ), args, valInfo ); }
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); }
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; }