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; }
/// <summary> /// Creates a rule for the contains operator. This is exposed via "x in y" in /// IronPython. It is implemented by calling the __contains__ method on x and /// passing in y. /// /// If a type doesn't define __contains__ but does define __getitem__ then __getitem__ is /// called repeatedly in order to see if the object is there. /// /// For normal .NET enumerables we'll walk the iterator and see if it's present. /// </summary> private static DynamicMetaObject/*!*/ MakeContainsOperation(PythonOperationBinder/*!*/ operation, DynamicMetaObject/*!*/[]/*!*/ types) { DynamicMetaObject res; // the paramteres come in backwards from how we look up __contains__, flip them. Debug.Assert(types.Length == 2); ArrayUtils.SwapLastTwo(types); PythonContext state = PythonContext.GetPythonContext(operation); SlotOrFunction sf = SlotOrFunction.GetSlotOrFunction(state, "__contains__", types); if (sf.Success) { // just a call to __contains__ res = sf.Target; } else { RestrictTypes(types); sf = SlotOrFunction.GetSlotOrFunction(state, "__iter__", types[0]); if (sf.Success) { // iterate using __iter__ res = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("ContainsFromEnumerable"), AstUtils.Constant(state.SharedContext), sf.Target.Expression, AstUtils.Convert(types[1].Expression, typeof(object)) ), BindingRestrictions.Combine(types) ); } else { ParameterExpression curIndex = Ast.Variable(typeof(int), "count"); sf = SlotOrFunction.GetSlotOrFunction(state, "__getitem__", types[0], new DynamicMetaObject(curIndex, BindingRestrictions.Empty)); if (sf.Success) { // defines __getitem__, need to loop over the indexes and see if we match ParameterExpression getItemRes = Ast.Variable(sf.ReturnType, "getItemRes"); ParameterExpression containsRes = Ast.Variable(typeof(bool), "containsRes"); LabelTarget target = Ast.Label(); res = new DynamicMetaObject( Ast.Block( new ParameterExpression[] { curIndex, getItemRes, containsRes }, Utils.Loop( null, // test Ast.Assign(curIndex, Ast.Add(curIndex, AstUtils.Constant(1))), // increment Ast.Block( // body // getItemRes = param0.__getitem__(curIndex) Utils.Try( Ast.Block( Ast.Assign( getItemRes, sf.Target.Expression ), Ast.Empty() ) ).Catch( // end of indexes, return false typeof(IndexOutOfRangeException), Ast.Break(target) ), // if(getItemRes == param1) return true Utils.If( DynamicExpression.Dynamic( state.BinaryOperationRetType( state.BinaryOperation(ExpressionType.Equal), state.Convert(typeof(bool), ConversionResultKind.ExplicitCast) ), typeof(bool), types[1].Expression, getItemRes ), Ast.Assign(containsRes, AstUtils.Constant(true)), Ast.Break(target) ), AstUtils.Empty() ), null, // loop else target, // break label target null ), containsRes ), BindingRestrictions.Combine(types) ); } else { // non-iterable object res = new DynamicMetaObject( operation.Throw( Ast.Call( typeof(PythonOps).GetMethod("TypeErrorForNonIterableObject"), AstUtils.Convert( types[1].Expression, typeof(object) ) ), typeof(bool) ), BindingRestrictions.Combine(types) ); } } } if (res.GetLimitType() != typeof(bool) && res.GetLimitType() != typeof(void)) { res = new DynamicMetaObject( DynamicExpression.Dynamic( state.Convert( typeof(bool), ConversionResultKind.ExplicitCast ), typeof(bool), res.Expression ), res.Restrictions ); } return res; }