public override DynamicMetaObject FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion) { var restricted = target.Restrict(target.RuntimeType); return(new DynamicMetaObject( Expression.Convert(restricted.Expression, Type), restricted.Restrictions)); }
private DynamicMetaObject /*!*/ MakeToBoolConversion(DynamicMetaObject /*!*/ self) { DynamicMetaObject res; 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( AstUtils.Constant(true), self.Restrictions )); } return(res); }
protected static DynamicMetaObject GetMemberFallback(DynamicMetaObject self, DynamicMetaObjectBinder member, DynamicMetaObject codeContext) { if (member is PythonGetMemberBinder gmb) { return(gmb.Fallback(self, codeContext)); } GetMemberBinder gma = (GetMemberBinder)member; return(gma.FallbackGetMember(self.Restrict(self.GetLimitType()))); }
private static 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 )); }
public DynamicMetaObject DeleteMember(string name, DynamicMetaObject target, OverloadResolverFactory resolutionFactory, DynamicMetaObject errorSuggestion) { ContractUtils.RequiresNotNull(name, "name"); ContractUtils.RequiresNotNull(target, "target"); return(MakeDeleteMemberTarget( new SetOrDeleteMemberInfo( name, resolutionFactory ), target.Restrict(target.GetLimitType()), errorSuggestion )); }
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(errorSuggestion ?? new DynamicMetaObject( Expression.Constant(OperationFailed.Value, typeof(object)), target.Restrict(CompilerHelpers.GetType(target.Value)).Restrictions )); }
DynamicMetaObject MakeGetMemberTarget(GetMemberInfo info, DynamicMetaObject target) { var type = target.GetLimitType(); var restrictions = target.Restrictions; var self = target; target = target.Restrict(target.GetLimitType()); var members = MemberGroup.EmptyGroup; // メンバ取得対象が TypeTracker である場合 if (typeof(TypeTracker).IsAssignableFrom(type)) { restrictions = restrictions.Merge(BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value)); var tg = target.Value as TypeGroup; if (tg == null || tg.TypesByArity.ContainsKey(0)) { var targetedType = ((TypeTracker)target.Value).Type; members = GetMember(MemberRequestKind.Get, targetedType, info.Name); if (members.Count > 0) { type = targetedType; self = null; } } } // 通常のメンバ一覧を検索 if (members.Count == 0) { members = GetMember(MemberRequestKind.Get, type, info.Name); } // インターフェイスの場合、object メンバを検索 if (members.Count == 0 && type.IsInterface) { members = GetMember(MemberRequestKind.Get, type = typeof(object), info.Name); } // プロパティ・フィールド用に StrongBox を展開し、そこから検索 var expandedSelf = self; if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(type) && expandedSelf != null) { expandedSelf = new DynamicMetaObject(Expression.Field(AstUtils.Convert(expandedSelf.Expression, type), type.GetField("Value")), expandedSelf.Restrictions, ((IStrongBox)expandedSelf.Value).Value); type = type.GetGenericArguments()[0]; members = GetMember(MemberRequestKind.Get, type, info.Name); } MakeBodyHelper(info, self, expandedSelf, type, members); return(info.Body.GetMetaObject(restrictions)); }
private static 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); }
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 )); }
private DynamicMetaObject MakeSetMemberTarget(SetOrDeleteMemberInfo memInfo, DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion) { Type type = target.GetLimitType(); DynamicMetaObject self = target; 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, errorSuggestion); return(memInfo.Body.GetMetaObject(target, value)); }
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 )); }
private static DynamicMetaObject MakeUnaryOperation(DynamicMetaObjectBinder binder, DynamicMetaObject self, TotemOperationKind symbol, DynamicMetaObject errorSuggestion, Type retType) { self = self.Restrict(self.GetLimitType()); throw new NotImplementedException(); }
private static DynamicMetaObject/*!*/ MakeUnaryNotOperation(DynamicMetaObjectBinder/*!*/ operation, DynamicMetaObject/*!*/ self, Type retType, DynamicMetaObject errorSuggestion) { self = self.Restrict(self.GetLimitType()); SlotOrFunction nonzero = SlotOrFunction.GetSlotOrFunction(PythonContext.GetPythonContext(operation), "__nonzero__", self); SlotOrFunction length = SlotOrFunction.GetSlotOrFunction(PythonContext.GetPythonContext(operation), "__len__", self); Expression notExpr; if (!nonzero.Success && !length.Success) { // no __len__ or __nonzero__, for None this is always false, everything else is True. If we have // an error suggestion though we'll go with that. if (errorSuggestion == null) { notExpr = (self.GetLimitType() == typeof(DynamicNull)) ? AstUtils.Constant(true) : AstUtils.Constant(false); } else { notExpr = errorSuggestion.Expression; } } else { SlotOrFunction target = nonzero.Success ? nonzero : length; notExpr = target.Target.Expression; if (nonzero.Success) { // call non-zero and negate it if (notExpr.Type == typeof(bool)) { notExpr = Ast.Equal(notExpr, AstUtils.Constant(false)); } else { notExpr = Ast.Call( typeof(PythonOps).GetMethod("Not"), AstUtils.Convert(notExpr, typeof(object)) ); } } else { // call len, compare w/ zero if (notExpr.Type == typeof(int)) { notExpr = Ast.Equal(notExpr, AstUtils.Constant(0)); } else { notExpr = Ast.Equal( DynamicExpression.Dynamic( PythonContext.GetPythonContext(operation).Operation( PythonOperationKind.Compare ), typeof(int), notExpr, AstUtils.Constant(0) ), AstUtils.Constant(0) ); } } } if (retType == typeof(object) && notExpr.Type == typeof(bool)) { notExpr = BindingHelpers.AddPythonBoxing(notExpr); } return new DynamicMetaObject( notExpr, self.Restrictions.Merge(nonzero.Target.Restrictions.Merge(length.Target.Restrictions)) ); }
internal DynamicMetaObject FallbackConvert(Type returnType, DynamicMetaObject self, DynamicMetaObject errorSuggestion) { 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.String: if (self.GetLimitType() == typeof(Bytes) && !_context.PythonOptions.Python30) { res = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("MakeString"), AstUtils.Convert(self.Expression, typeof(IList <byte>)) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(Bytes)) ); } 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 <>)) { if (self.LimitType == typeof(string)) { res = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("MakeByteArray"), AstUtils.Convert(self.Expression, typeof(string)) ), BindingRestrictions.GetTypeRestriction( self.Expression, typeof(string) ) ); } else { 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 (!typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self)) { res = 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 = 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)), AstUtils.Constant(Activator.CreateInstance(self.GetLimitType())) ), AstUtils.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 ?? EnsureReturnType(returnType, Context.Binder.ConvertTo(Type, ResultKind, self, _context.SharedOverloadResolverFactory, errorSuggestion))); }
private static DynamicMetaObject MakeUnaryOperation(DynamicMetaObjectBinder binder, DynamicMetaObject self, string symbol, DynamicMetaObject errorSuggestion) { self = self.Restrict(self.GetLimitType()); SlotOrFunction func = SlotOrFunction.GetSlotOrFunction(PythonContext.GetPythonContext(binder), symbol, self); if (!func.Success) { // we get the error message w/ {0} so that PythonBinderHelper.TypeError formats it correctly return errorSuggestion ?? TypeError(binder, MakeUnaryOpErrorMessage(symbol, "{0}"), self); } return func.Target; }
private static DynamicMetaObject MakeEnumeratorOperation(PythonOperationBinder operation, DynamicMetaObject self) { if (self.GetLimitType() == typeof(string)) { self = self.Restrict(self.GetLimitType()); return new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod("StringEnumerator"), self.Expression ), self.Restrictions ); } else if (self.GetLimitType() == typeof(Bytes)) { self = self.Restrict(self.GetLimitType()); if (operation.Context.PythonOptions.Python30) { return new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod("BytesIntEnumerator"), self.Expression ), self.Restrictions ); } else { return new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod("BytesEnumerator"), self.Expression ), self.Restrictions ); } } else if ((self.Value is IEnumerable || typeof(IEnumerable).IsAssignableFrom(self.GetLimitType())) && !(self.Value is PythonGenerator)) { self = self.Restrict(self.GetLimitType()); return new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod("GetEnumeratorFromEnumerable"), Expression.Convert( self.Expression, typeof(IEnumerable) ) ), self.Restrictions ); } else if (self.Value is IEnumerator || // check for COM object (and fast check when we have values) typeof(IEnumerator).IsAssignableFrom(self.GetLimitType())) { // check if we don't have a value DynamicMetaObject ieres = new DynamicMetaObject( MakeEnumeratorResult( Ast.Convert( self.Expression, typeof(IEnumerator) ) ), self.Restrict(self.GetLimitType()).Restrictions ); #if FEATURE_COM if (Microsoft.Scripting.ComInterop.ComBinder.IsComObject(self.Value)) { ieres = new DynamicMetaObject( MakeEnumeratorResult( Expression.Convert( self.Expression, typeof(IEnumerator) ) ), ieres.Restrictions.Merge( BindingRestrictions.GetExpressionRestriction( Ast.TypeIs(self.Expression, typeof(IEnumerator)) ) ) ); } #endif return ieres; } ParameterExpression tmp = Ast.Parameter(typeof(IEnumerator), "enum"); IPythonConvertible pyConv = self as IPythonConvertible; PythonConversionBinder convBinder = PythonContext.GetPythonContext(operation).Convert(typeof(IEnumerator), ConversionResultKind.ExplicitTry); DynamicMetaObject res; if (pyConv != null) { res = pyConv.BindConvert(convBinder); } else { res = convBinder.Bind(self, new DynamicMetaObject[0]); } return new DynamicMetaObject( Expression.Block( new[] { tmp }, Ast.Condition( Ast.NotEqual( Ast.Assign(tmp, res.Expression), AstUtils.Constant(null) ), MakeEnumeratorResult(tmp), Ast.Call( typeof(PythonOps).GetMethod("ThrowTypeErrorForBadIteration"), PythonContext.GetCodeContext(operation), self.Expression ) ) ), res.Restrictions ); }
/// <summary> /// Called when the user is expanding a dictionary - we copy the user /// dictionary and verify that it contains only valid string names. /// </summary> private DynamicMetaObject/*!*/ MakeDictionaryCopy(DynamicMetaObject/*!*/ userDict) { Debug.Assert(_dict == null); userDict = userDict.Restrict(userDict.GetLimitType()); _temps.Add(_dict = Ast.Variable(typeof(PythonDictionary), "$dict")); EnsureInit(); string methodName; if (typeof(PythonDictionary).IsAssignableFrom(userDict.GetLimitType())) { methodName = "CopyAndVerifyPythonDictionary"; } else if (typeof(IDictionary).IsAssignableFrom(userDict.GetLimitType())) { methodName = "CopyAndVerifyDictionary"; } else { methodName = "CopyAndVerifyUserMapping"; } _init.Add( Ast.Assign( _dict, Ast.Call( typeof(PythonOps).GetMethod(methodName), GetFunctionParam(), AstUtils.Convert(userDict.Expression, userDict.GetLimitType()) ) ) ); return userDict; }
private static DynamicMetaObject/*!*/ MakeHashOperation(PythonOperationBinder/*!*/ operation, DynamicMetaObject/*!*/ self) { self = self.Restrict(self.GetLimitType()); PythonContext state = PythonContext.GetPythonContext(operation); SlotOrFunction func = SlotOrFunction.GetSlotOrFunction(state, "__hash__", self); DynamicMetaObject res = func.Target; if (func.IsNull) { // Python 2.6 setting __hash__ = None makes the type unhashable res = new DynamicMetaObject( operation.Throw( Expression.Call( typeof(PythonOps).GetMethod("TypeErrorForUnhashableObject"), self.Expression ), typeof(int) ), res.Restrictions ); } else if (func.ReturnType != typeof(int)) { if (func.ReturnType == typeof(BigInteger)) { // Python 2.5 defines the result of returning a long as hashing the long res = new DynamicMetaObject( HashBigInt(operation, res.Expression), res.Restrictions ); } else if (func.ReturnType == typeof(object)) { // need to get the integer value here... ParameterExpression tempVar = Ast.Parameter(typeof(object), "hashTemp"); res = new DynamicMetaObject( Expression.Block( new[] { tempVar }, Expression.Assign(tempVar, res.Expression), Expression.Condition( Expression.TypeIs(tempVar, typeof(int)), Expression.Convert(tempVar, typeof(int)), Expression.Condition( Expression.TypeIs(tempVar, typeof(BigInteger)), HashBigInt(operation, tempVar), HashConvertToInt(state, tempVar) ) ) ), res.Restrictions ); } else { // need to convert unknown value to object res = new DynamicMetaObject( HashConvertToInt(state, res.Expression), res.Restrictions ); } } return res; }
private static DynamicMetaObject/*!*/ MakeUnaryOperation(OperationBinder/*!*/ operation, DynamicMetaObject/*!*/ self) { self = self.Restrict(self.GetLimitType()); SlotOrFunction func = SlotOrFunction.GetSlotOrFunction(BinderState.GetBinderState(operation), Symbols.OperatorToSymbol(operation.Operation), self); if (!func.Success) { // we get the error message w/ {0} so that PythonBinderHelper.TypeError formats it correctly return TypeError(operation, MakeUnaryOpErrorMessage(operation.Operation.ToString(), "{0}"), self); } return func.Target; }
private DynamicMetaObject MakeGetMemberTarget(GetMemberInfo getMemInfo, DynamicMetaObject target) { Type targetType = 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(targetType)) { restrictions = restrictions.Merge( BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value) ); TypeGroup tg = target.Value as TypeGroup; if (tg == null || tg.TryGetNonGenericType(out Type _)) { 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... targetType = ((TypeTracker)target.Value).Type; self = null; } } } if (members.Count == 0) { // Get the members members = GetMember(MemberRequestKind.Get, targetType, getMemInfo.Name); } if (members.Count == 0) { if (typeof(TypeTracker).IsAssignableFrom(targetType)) { // Throws an exception if 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. EnsureTrackerRepresentsNonGenericType((TypeTracker)target.Value); } else if (targetType.IsInterface) { // all interfaces have object members targetType = typeof(object); members = GetMember(MemberRequestKind.Get, targetType, getMemInfo.Name); } } DynamicMetaObject propSelf = self; // if lookup failed try the strong-box type if available. if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(targetType) && propSelf != null) { // properties/fields need the direct value, methods hold onto the strong box. propSelf = new DynamicMetaObject( Expression.Field(AstUtils.Convert(propSelf.Expression, targetType), targetType.GetInheritedFields("Value").First()), propSelf.Restrictions, ((IStrongBox)propSelf.Value).Value ); targetType = targetType.GetGenericArguments()[0]; members = GetMember( MemberRequestKind.Get, targetType, getMemInfo.Name ); } MakeBodyHelper(getMemInfo, self, propSelf, targetType, members); getMemInfo.Body.Restrictions = restrictions; return(getMemInfo.Body.GetMetaObject(target)); }
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); PythonContext pyContext = PythonContext.GetPythonContext(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(pyContext.SharedContext, "__call__", out callSlot)) { ConditionalBuilder cb = new ConditionalBuilder(call); callSlot.MakeGetExpression( pyContext.Binder, PythonContext.GetCodeContext(call), self, GetPythonType(self), cb ); if (!cb.IsFinal) { cb.FinishCondition(GetCallError(call, self)); } Expression[] callArgs = ArrayUtils.Insert( PythonContext.GetCodeContext(call), cb.GetMetaObject().Expression, DynamicUtils.GetExpressions(args) ); Expression body = DynamicExpression.Dynamic( PythonContext.GetPythonContext(call).Invoke( BindingHelpers.GetCallSignature(call) ), typeof(object), callArgs ); body = Ast.TryFinally( Ast.Block( Ast.Call(typeof(PythonOps).GetMethod(nameof(PythonOps.FunctionPushFrame)), Ast.Constant(pyContext)), body ), Ast.Call(typeof(PythonOps).GetMethod(nameof(PythonOps.FunctionPopFrame))) ); return(BindingHelpers.AddDynamicTestAndDefer( call, new DynamicMetaObject(body, self.Restrictions.Merge(BindingRestrictions.Combine(args))), args, valInfo )); } return(null); }
///------------------------------------------------------------------------------------------------- /// <summary> /// Called when the user is expanding a dictionary - we copy the user /// dictionary and verify that it contains only valid string names. /// </summary> /// /// <remarks> Aleksander, 19.05.2013. </remarks> /// /// <param name="userDict"> Dictionary of users. </param> /// /// <returns> . </returns> ///------------------------------------------------------------------------------------------------- private DynamicMetaObject MakeDictionaryCopy(DynamicMetaObject userDict) { Debug.Assert(_dict == null); userDict = userDict.Restrict(userDict.GetLimitType()); _temps.Add(_dict = Expression.Variable(typeof(TotemDictionary), "$dict")); EnsureInit(); MethodInfo method; if (typeof(TotemDictionary).IsAssignableFrom(userDict.GetLimitType())) method = AstMethods.CopyAndVerifyTotemDictionary; else if (typeof(IDictionary).IsAssignableFrom(userDict.GetLimitType())) method = AstMethods.CopyAndVerifyDictionary; else method = AstMethods.CopyAndVerifyUserMapping; _init.Add( Expression.Assign( _dict, Expression.Call( method, GetFunctionParam(), Utils.Convert(userDict.Expression, userDict.GetLimitType()) ) ) ); return userDict; }
/// <summary> /// Transforms a call into a Python GetMember/Invoke. This isn't quite the correct semantic as /// we shouldn't be returning Python members (e.g. object.__repr__) to non-Python callers. This /// can go away as soon as all of the classes implement the full fidelity of the protocol /// </summary> internal static DynamicMetaObject/*!*/ GenericCall(InvokeMemberBinder/*!*/ action, DynamicMetaObject target, DynamicMetaObject/*!*/[]/*!*/ args) { if (target.NeedsDeferral()) { return action.Defer(args); } return new DynamicMetaObject( Invoke( BinderState.GetCodeContext(action), BinderState.GetBinderState(action), typeof(object), GetCallSignature(action), ArrayUtils.Insert( Binders.Get( BinderState.GetCodeContext(action), BinderState.GetBinderState(action), typeof(object), action.Name, target.Expression ), DynamicUtils.GetExpressions(args) ) ), BindingRestrictions.Combine(args).Merge(target.Restrict(target.GetLimitType()).Restrictions) ); }
/// <summary> /// target is the newly initialized value. /// args are the arguments to be passed to __init__ /// </summary> public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) { DynamicMetaObject codeContext = target; CodeContext context = (CodeContext)codeContext.Value; target = args[0]; args = ArrayUtils.RemoveFirst(args); ValidationInfo valInfo = BindingHelpers.GetValidationInfo(target); Expression res; PythonType instType = DynamicHelpers.GetPythonType(target.Value); BindingRestrictions initRestrictions = BindingRestrictions.Empty; if (IronPython.Modules.Builtin.isinstance(target.Value, _newType) && NeedsInitCall((CodeContext)codeContext.Value, instType, args.Length)) { // resolve __init__ PythonTypeSlot init; instType.TryResolveSlot(context, "__init__", out init); if (init is PythonFunction) { // avoid creating the bound method, just invoke it directly Expression[] allArgs = new Expression[args.Length + 3]; allArgs[0] = codeContext.Expression; allArgs[1] = AstUtils.WeakConstant(init); allArgs[2] = target.Expression; for (int i = 0; i < args.Length; i++) { allArgs[3 + i] = args[i].Expression; } res = DynamicExpression.Dynamic( context.LanguageContext.Invoke(_signature.InsertArgument(Argument.Simple)), typeof(object), allArgs ); } else if (init is BuiltinMethodDescriptor || init is BuiltinFunction) { IList <MethodBase> targets; if (init is BuiltinMethodDescriptor) { targets = ((BuiltinMethodDescriptor)init).Template.Targets; } else { targets = ((BuiltinFunction)init).Targets; } PythonBinder binder = context.LanguageContext.Binder; DynamicMetaObject initInvoke = binder.CallMethod( new PythonOverloadResolver( binder, target, args, _signature, codeContext.Expression ), targets, BindingRestrictions.Empty ); res = initInvoke.Expression; initRestrictions = initInvoke.Restrictions; } else { // some weird descriptor has been put in place for __init__, we need // to call __get__ on it each time. res = MakeDynamicInitInvoke( context, args, Expression.Call( typeof(PythonOps).GetMethod("GetInitSlotMember"), codeContext.Expression, Expression.Convert(AstUtils.WeakConstant(_newType), typeof(PythonType)), Expression.Convert(AstUtils.WeakConstant(init), typeof(PythonTypeSlot)), AstUtils.Convert(target.Expression, typeof(object)) ), codeContext.Expression ); } } else { // returned something that isn't a subclass of the creating type // __init__ will not be run. res = AstUtils.Empty(); } // check for __del__ PythonTypeSlot delSlot; if (instType.TryResolveSlot(context, "__del__", out delSlot)) { res = Expression.Block( res, Expression.Call( typeof(PythonOps).GetMethod("InitializeForFinalization"), codeContext.Expression, AstUtils.Convert(target.Expression, typeof(object)) ) ); } return(BindingHelpers.AddDynamicTestAndDefer( this, new DynamicMetaObject( Expression.Block( res, target.Expression ), target.Restrict(target.LimitType).Restrictions.Merge(initRestrictions) ), args, valInfo )); }
private DynamicMetaObject/*!*/ MakeConvertRuleForCall(ConvertBinder/*!*/ convertToAction, DynamicMetaObject/*!*/ self, SymbolId symbolId, string returner) { PythonType pt = ((IPythonObject)self.Value).PythonType; PythonTypeSlot pts; CodeContext context = BinderState.GetBinderState(convertToAction).Context; if (pt.TryResolveSlot(context, symbolId, out pts) && !IsBuiltinConversion(context, pts, symbolId, pt)) { ParameterExpression tmp = Ast.Variable(typeof(object), "func"); Expression callExpr = Ast.Call( PythonOps.GetConversionHelper(returner, GetResultKind(convertToAction)), Ast.Dynamic( new PythonInvokeBinder( BinderState.GetBinderState(convertToAction), new CallSignature(0) ), typeof(object), BinderState.GetCodeContext(convertToAction), tmp ) ); if (typeof(Extensible<>).MakeGenericType(convertToAction.Type).IsAssignableFrom(self.GetLimitType())) { // if we're doing a conversion to the underlying type and we're an // Extensible<T> of that type: // if an extensible type returns it's self in a conversion, then we need // to actually return the underlying value. If an extensible just keeps // returning more instances of it's self a stack overflow occurs - both // behaviors match CPython. callExpr = AstUtils.Convert(AddExtensibleSelfCheck(convertToAction, self, callExpr), typeof(object)); } return new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( BindingHelpers.CheckTypeVersion( self.Expression, pt.Version ), Ast.Condition( MakeTryGetTypeMember( BinderState.GetBinderState(convertToAction), pts, self.Expression, tmp ), callExpr, AstUtils.Convert( ConversionFallback(convertToAction), typeof(object) ) ), convertToAction.Defer(this).Expression ) ), self.Restrict(self.GetRuntimeType()).Restrictions ); } return convertToAction.FallbackConvert(this); }
private static DynamicMetaObject MakeEnumeratorOperation(PythonOperationBinder operation, DynamicMetaObject self) { if (self.GetLimitType() == typeof(string)) { self = self.Restrict(self.GetLimitType()); return new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod("StringEnumerator"), self.Expression ), self.Restrictions ); } else if (self.GetLimitType() == typeof(PythonDictionary)) { self = self.Restrict(self.GetLimitType()); return new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod("MakeDictionaryKeyEnumerator"), self.Expression ), self.Restrictions ); } else if (self.Value is IEnumerable || typeof(IEnumerable).IsAssignableFrom(self.GetLimitType())) { self = self.Restrict(self.GetLimitType()); return new DynamicMetaObject( Expression.Call( Expression.Convert( self.Expression, typeof(IEnumerable) ), typeof(IEnumerable).GetMethod("GetEnumerator") ), self.Restrictions ); } else if (self.Value is IEnumerator || // check for COM object (and fast check when we have values) typeof(IEnumerator).IsAssignableFrom(self.GetLimitType())) { // check if we don't have a value DynamicMetaObject ieres = self.Restrict(self.GetLimitType()); #if !SILVERLIGHT if (ComOps.IsComObject(self.Value)) { ieres = new DynamicMetaObject( self.Expression, ieres.Restrictions.Merge( BindingRestrictions.GetExpressionRestriction( Ast.TypeIs(self.Expression, typeof(IEnumerator)) ) ) ); } #endif return ieres; } ParameterExpression tmp = Ast.Parameter(typeof(IEnumerator), "enum"); DynamicMetaObject res = self.BindConvert(new ConversionBinder(BinderState.GetBinderState(operation), typeof(IEnumerator), ConversionResultKind.ExplicitTry)); return new DynamicMetaObject( Expression.Block( new[] { tmp }, Ast.Condition( Ast.NotEqual( Ast.Assign(tmp, res.Expression), AstUtils.Constant(null) ), tmp, Ast.Call( typeof(PythonOps).GetMethod("ThrowTypeErrorForBadIteration"), BinderState.GetCodeContext(operation), self.Expression ) ) ), res.Restrictions ); }
private static DynamicMetaObject/*!*/ MakeHashOperation(PythonOperationBinder/*!*/ operation, DynamicMetaObject/*!*/ self) { self = self.Restrict(self.GetLimitType()); BinderState state = BinderState.GetBinderState(operation); SlotOrFunction func = SlotOrFunction.GetSlotOrFunction(state, Symbols.Hash, self); DynamicMetaObject res = func.Target; if (func.ReturnType != typeof(int)) { if (func.ReturnType == typeof(BigInteger)) { // Python 2.5 defines the result of returning a long as hashing the long res = new DynamicMetaObject( HashBigInt(operation, res.Expression), res.Restrictions ); } else if (func.ReturnType == typeof(object)) { // need to get the integer value here... ParameterExpression tempVar = Ast.Parameter(typeof(object), "hashTemp"); res = new DynamicMetaObject( Expression.Block( new [] { tempVar }, Expression.Assign(tempVar, res.Expression), Expression.Condition( Expression.TypeIs(tempVar, typeof(int)), Expression.Convert(tempVar, typeof(int)), Expression.Condition( Expression.TypeIs(tempVar, typeof(BigInteger)), HashBigInt(operation, tempVar), HashConvertToInt(state, tempVar) ) ) ), res.Restrictions ); } else { // need to convert unknown value to object res = new DynamicMetaObject( HashConvertToInt(state, res.Expression), res.Restrictions ); } } return res; }
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"), AstUtils.Constant(0) ), self.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Ast.Equal(getLen, AstUtils.Constant(1)))) ); } else { res = new DynamicMetaObject( Ast.Throw( Ast.Call( typeof(PythonOps).GetMethod("TypeError"), AstUtils.Constant("expected string of length 1 when converting to char, got '{0}'"), Ast.NewArrayInit(typeof(object), self.Expression) ), ReturnType ), self.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Ast.NotEqual(getLen, AstUtils.Constant(1)))) ); } } else { // let the base class produce the rule res = null; } return(res); }
private static DynamicMetaObject/*!*/ MakeUnaryNotOperation(DynamicMetaObjectBinder/*!*/ operation, DynamicMetaObject/*!*/ self, Type/*!*/ retType) { self = self.Restrict(self.GetLimitType()); SlotOrFunction nonzero = SlotOrFunction.GetSlotOrFunction(PythonContext.GetPythonContext(operation), Symbols.NonZero, self); SlotOrFunction length = SlotOrFunction.GetSlotOrFunction(PythonContext.GetPythonContext(operation), Symbols.Length, self); Expression notExpr; if (!nonzero.Success && !length.Success) { // always False or True for None notExpr = (self.GetLimitType() == typeof(DynamicNull)) ? AstUtils.Constant(true) : AstUtils.Constant(false); } else { SlotOrFunction target = nonzero.Success ? nonzero : length; notExpr = target.Target.Expression; if (nonzero.Success) { // call non-zero and negate it if (notExpr.Type == typeof(bool)) { notExpr = Ast.Equal(notExpr, AstUtils.Constant(false)); } else { notExpr = Ast.Call( typeof(PythonOps).GetMethod("Not"), AstUtils.Convert(notExpr, typeof(object)) ); } } else { // call len, compare w/ zero if (notExpr.Type == typeof(int)) { notExpr = Ast.Equal(notExpr, AstUtils.Constant(0)); } else { notExpr = Ast.Equal( Ast.Dynamic( PythonContext.GetPythonContext(operation).Operation( PythonOperationKind.Compare ), typeof(int), notExpr, AstUtils.Constant(0) ), AstUtils.Constant(0) ); } } } Debug.Assert(notExpr.Type == typeof(bool)); if (retType == typeof(object)) { notExpr = BindingHelpers.AddPythonBoxing(notExpr); } return new DynamicMetaObject( notExpr, self.Restrictions.Merge(nonzero.Target.Restrictions.Merge(length.Target.Restrictions)) ); }
private DynamicMetaObject /*!*/ MakeConvertRuleForCall(DynamicMetaObjectBinder /*!*/ convertToAction, Type toType, DynamicMetaObject /*!*/ self, string name, string returner, Func <DynamicMetaObject> fallback, Func <Expression, Expression> resultConverter) { PythonType pt = ((IPythonObject)self.Value).PythonType; PythonTypeSlot pts; CodeContext context = PythonContext.GetPythonContext(convertToAction).SharedContext; ValidationInfo valInfo = BindingHelpers.GetValidationInfo(this, pt); if (pt.TryResolveSlot(context, name, out pts) && !IsBuiltinConversion(context, pts, name, pt)) { ParameterExpression tmp = Ast.Variable(typeof(object), "func"); Expression callExpr = resultConverter( Ast.Call( PythonOps.GetConversionHelper(returner, GetResultKind(convertToAction)), Ast.Dynamic( PythonContext.GetPythonContext(convertToAction).InvokeNone, typeof(object), PythonContext.GetCodeContext(convertToAction), tmp ) ) ); if (typeof(Extensible <>).MakeGenericType(toType).IsAssignableFrom(self.GetLimitType())) { // if we're doing a conversion to the underlying type and we're an // Extensible<T> of that type: // if an extensible type returns it's self in a conversion, then we need // to actually return the underlying value. If an extensible just keeps // returning more instances of it's self a stack overflow occurs - both // behaviors match CPython. callExpr = AstUtils.Convert(AddExtensibleSelfCheck(convertToAction, toType, self, callExpr), typeof(object)); } return(BindingHelpers.AddDynamicTestAndDefer( convertToAction, new DynamicMetaObject( Ast.Condition( MakeTryGetTypeMember( PythonContext.GetPythonContext(convertToAction), pts, self.Expression, tmp ), callExpr, AstUtils.Convert( ConversionFallback(convertToAction), typeof(object) ) ), self.Restrict(self.GetRuntimeType()).Restrictions ), new DynamicMetaObject[] { this }, valInfo, tmp )); } return(fallback()); }
private DynamicMetaObject/*!*/ MakeConvertRuleForCall(DynamicMetaObjectBinder/*!*/ convertToAction, Type toType, DynamicMetaObject/*!*/ self, string name, string returner, Func<DynamicMetaObject> fallback, Func<Expression, Expression> resultConverter) { PythonType pt = ((IPythonObject)self.Value).PythonType; PythonTypeSlot pts; CodeContext context = PythonContext.GetPythonContext(convertToAction).SharedContext; ValidationInfo valInfo = BindingHelpers.GetValidationInfo(this, pt); if (pt.TryResolveSlot(context, name, out pts) && !IsBuiltinConversion(context, pts, name, pt)) { ParameterExpression tmp = Ast.Variable(typeof(object), "func"); Expression callExpr = resultConverter( Ast.Call( PythonOps.GetConversionHelper(returner, GetResultKind(convertToAction)), Ast.Dynamic( PythonContext.GetPythonContext(convertToAction).InvokeNone, typeof(object), PythonContext.GetCodeContext(convertToAction), tmp ) ) ); if (typeof(Extensible<>).MakeGenericType(toType).IsAssignableFrom(self.GetLimitType())) { // if we're doing a conversion to the underlying type and we're an // Extensible<T> of that type: // if an extensible type returns it's self in a conversion, then we need // to actually return the underlying value. If an extensible just keeps // returning more instances of it's self a stack overflow occurs - both // behaviors match CPython. callExpr = AstUtils.Convert(AddExtensibleSelfCheck(convertToAction, toType, self, callExpr), typeof(object)); } return BindingHelpers.AddDynamicTestAndDefer( convertToAction, new DynamicMetaObject( Ast.Condition( MakeTryGetTypeMember( PythonContext.GetPythonContext(convertToAction), pts, self.Expression, tmp ), callExpr, AstUtils.Convert( ConversionFallback(convertToAction), typeof(object) ) ), self.Restrict(self.GetRuntimeType()).Restrictions ), new DynamicMetaObject[] { this }, valInfo, tmp ); } return fallback(); }