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(); }
public DynamicMetaObject DeleteMember(string name, DynamicMetaObject target, Expression codeContext) { ContractUtils.RequiresNotNull(name, "name"); ContractUtils.RequiresNotNull(target, "target"); return MakeDeleteMemberTarget( new SetOrDeleteMemberInfo( name, codeContext ), target.Restrict(target.GetLimitType()) ); }
public DynamicMetaObject DeleteMember(string name, DynamicMetaObject target, OverloadResolverFactory resolutionFactory) { ContractUtils.RequiresNotNull(name, "name"); ContractUtils.RequiresNotNull(target, "target"); return MakeDeleteMemberTarget( new SetOrDeleteMemberInfo( name, resolutionFactory ), target.Restrict(target.GetLimitType()) ); }
private DynamicMetaObject MakeSetMemberTarget(SetOrDeleteMemberInfo memInfo, DynamicMetaObject target, DynamicMetaObject value) { Type type = target.GetLimitType(); Expression self = target.Expression; 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); return memInfo.Body.GetMetaObject(target, value); }
protected static DynamicMetaObject GetMemberFallback(DynamicMetaObject self, DynamicMetaObjectBinder member, DynamicMetaObject codeContext) { PythonGetMemberBinder gmb = member as PythonGetMemberBinder; if (gmb != null) { return gmb.Fallback(self, codeContext); } GetMemberBinder gma = (GetMemberBinder)member; return gma.FallbackGetMember(self.Restrict(self.GetLimitType())); }
private DynamicMetaObject MakeGetMemberTarget(GetMemberInfo getMemInfo, DynamicMetaObject target) { Type type = target.GetLimitType(); BindingRestrictions restrictions = target.Restrictions; Expression self = target.Expression; target = target.Restrict(target.GetLimitType()); // needed for GetMember call until DynamicAction goes away OldDynamicAction act = OldGetMemberAction.Make( this, getMemInfo.Name ); // Specially recognized types: TypeTracker, NamespaceTracker, and StrongBox. // TODO: TypeTracker and NamespaceTracker should technically be IDO's. MemberGroup members = MemberGroup.EmptyGroup; if (typeof(TypeTracker).IsAssignableFrom(type)) { restrictions = restrictions.Merge( BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value) ); TypeGroup tg = target.Value as TypeGroup; Type nonGen; if (tg == null || tg.TryGetNonGenericType(out nonGen)) { members = GetMember(act, ((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... type = ((TypeTracker)target.Value).Type; self = null; } } } if (members.Count == 0) { // Get the members members = GetMember(act, type, getMemInfo.Name); } if (members.Count == 0) { if (typeof(TypeTracker).IsAssignableFrom(type)) { // ensure 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 Type x = ((TypeTracker)target.Value).Type; } else if (type.IsInterface) { // all interfaces have object members type = typeof(object); members = GetMember(act, type, getMemInfo.Name); } } Expression propSelf = self; // if lookup failed try the strong-box type if available. if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(type)) { // properties/fields need the direct value, methods hold onto the strong box. propSelf = Ast.Field(AstUtils.Convert(self, type), type.GetField("Value")); type = type.GetGenericArguments()[0]; members = GetMember( act, type, getMemInfo.Name ); } MakeBodyHelper(getMemInfo, self, propSelf, type, members); getMemInfo.Body.Restrictions = restrictions; return getMemInfo.Body.GetMetaObject(target); }
private DynamicMetaObject RestrictArgument(DynamicMetaObject arg, ParameterWrapper parameter) { if (parameter.Type == typeof(object)) { // don't use Restrict as it'll box & unbox. return new DynamicMetaObject(arg.Expression, BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg.Expression, arg.GetLimitType())); } else { return arg.Restrict(arg.GetLimitType()); } }
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 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; }
private 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 ); }
private 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 ); }
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 ); }
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 new DynamicMetaObject( Expression.Constant(OperationFailed.Value, typeof(object)), target.Restrict(CompilerHelpers.GetType(target.Value)).Restrictions ); }
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; }
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 MakeGetMemberTarget(GetMemberInfo getMemInfo, DynamicMetaObject target) { Type type = 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(type)) { restrictions = restrictions.Merge( BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value) ); TypeGroup tg = target.Value as TypeGroup; Type nonGen; if (tg == null || tg.TryGetNonGenericType(out nonGen)) { 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... type = ((TypeTracker)target.Value).Type; self = null; } } } if (members.Count == 0) { // Get the members members = GetMember(MemberRequestKind.Get, type, getMemInfo.Name); } if (members.Count == 0) { if (type.IsInterface) { // all interfaces have object members type = typeof(object); members = GetMember(MemberRequestKind.Get, type, getMemInfo.Name); } } DynamicMetaObject propSelf = self == null ? null : self; // if lookup failed try the strong-box type if available. if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(type) && propSelf != null) { // properties/fields need the direct value, methods hold onto the strong box. propSelf = new DynamicMetaObject( Ast.Field(AstUtils.Convert(propSelf.Expression, type), type.GetField("Value")), propSelf.Restrictions, ((IStrongBox)propSelf.Value).Value ); type = type.GetGenericArguments()[0]; members = GetMember( MemberRequestKind.Get, type, getMemInfo.Name ); } MakeBodyHelper(getMemInfo, self, propSelf, type, members); getMemInfo.Body.Restrictions = restrictions; return getMemInfo.Body.GetMetaObject(target); }