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; }
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"), Ast.Constant(0) ), self.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Ast.Equal(getLen, Ast.Constant(1)))) ); } else { res = new DynamicMetaObject( Ast.Throw( Ast.Call( typeof(PythonOps).GetMethod("TypeError"), Ast.Constant("expected string of length 1 when converting to char, got '{0}'"), Ast.NewArrayInit(typeof(object), self.Expression) ) ), self.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Ast.NotEqual(getLen, Ast.Constant(1)))) ); } } else { // let the base class produce the rule res = null; } return res; }