/// <summary> /// Creating a standard .NET type is easy - we just call it's constructor with the provided /// arguments. /// </summary> private DynamicMetaObject/*!*/ MakeStandardDotNetTypeCall(DynamicMetaObjectBinder/*!*/ call, Expression/*!*/ codeContext, DynamicMetaObject/*!*/[]/*!*/ args) { CallSignature signature = BindingHelpers.GetCallSignature(call); BinderState state = BinderState.GetBinderState(call); MethodBase[] ctors = CompilerHelpers.GetConstructors(Value.UnderlyingSystemType, state.Binder.PrivateBinding); if (ctors.Length > 0) { return state.Binder.CallMethod( new ParameterBinderWithCodeContext(state.Binder, codeContext), ctors, args, signature, Restrictions.Merge(BindingRestrictions.GetInstanceRestriction(Expression, Value)) ); } else { return new DynamicMetaObject( Ast.Throw( Ast.New( typeof(ArgumentTypeException).GetConstructor(new Type[] { typeof(string) }), Ast.Constant("Cannot create instances of " + Value.Name) ) ), Restrictions.Merge(BindingRestrictions.GetInstanceRestriction(Expression, Value)) ); } }
public DynamicMetaObject ConvertWorker(DynamicMetaObjectBinder binder, Type toType, ConversionResultKind kind) { if (toType.IsSubclassOf(typeof(Delegate))) { return MakeDelegateTarget(binder, toType, Restrict(typeof(Method))); } return FallbackConvert(binder); }
internal static bool IsNoThrow(DynamicMetaObjectBinder action) { PythonGetMemberBinder gmb = action as PythonGetMemberBinder; if (gmb != null) { return gmb.IsNoThrow; } return false; }
public Expression Dynamic(DynamicMetaObjectBinder binder, Type retType, Expression arg0, Expression arg1, Expression arg2, Expression arg3) { if(retType == typeof(object)) return new TotemDynamicExpression4(binder, this, arg0, arg1, arg2, arg3); else if(retType == typeof(bool)) return new TotemDynamicExpression4<bool>(binder, this, arg0, arg1, arg2, arg3); return ReduceDynamic(binder, retType, arg0, arg1, arg2, arg3); }
public DynamicMetaObject ConvertWorker(DynamicMetaObjectBinder binder, Type toType, ConversionResultKind kind) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "BuiltinFunc Convert " + toType); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "BuiltinFunc Convert"); if (toType.IsSubclassOf(typeof(Delegate))) { return MakeDelegateTarget(binder, toType, Restrict(LimitType)); } return FallbackConvert(binder); }
public DynamicMetaObject ConvertWorker(DynamicMetaObjectBinder binder, Type type, Type retType, ConversionResultKind kind) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "Conversion " + type.FullName); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "Conversion"); ValidationInfo typeTest = BindingHelpers.GetValidationInfo(this, Value.PythonType); return BindingHelpers.AddDynamicTestAndDefer( binder, TryPythonConversion(binder, type) ?? FallbackConvert(binder), new DynamicMetaObject[] { this }, typeTest, retType ); }
/*!*/ public MSAst.Expression Dynamic(DynamicMetaObjectBinder/*!*/ binder, Type/*!*/ retType, MSAst.Expression/*!*/ arg0) { if (retType == typeof(object)) { throw new NotImplementedException(); //return new TotemDynamicExpression1(binder, this, arg0); } else if (retType == typeof(bool)) { throw new NotImplementedException(); //return new TotemDynamicExpression1<bool>(binder, this, arg0); } return ReduceDynamic(binder, retType, arg0); }
private DynamicMetaObject/*!*/ InvokeWorker(DynamicMetaObjectBinder/*!*/ call, Expression/*!*/ codeContext, DynamicMetaObject/*!*/[] args) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "BuiltinMethodDesc Invoke " + Value.DeclaringType + "." + Value.__name__ + " w/ " + args.Length + " args"); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "BuiltinMethodDesc Invoke"); CallSignature signature = BindingHelpers.GetCallSignature(call); BindingRestrictions selfRestrict = BindingRestrictions.GetInstanceRestriction(Expression, Value).Merge(Restrictions); selfRestrict = selfRestrict.Merge( BindingRestrictions.GetExpressionRestriction( MakeFunctionTest( Ast.Call( typeof(PythonOps).GetMethod("GetBuiltinMethodDescriptorTemplate"), Ast.Convert(Expression, typeof(BuiltinMethodDescriptor)) ) ) ) ); return Value.Template.MakeBuiltinFunctionCall( call, codeContext, this, args, false, // no self selfRestrict, (newArgs) => { BindingTarget target; PythonContext state = PythonContext.GetPythonContext(call); DynamicMetaObject res = state.Binder.CallMethod( new PythonOverloadResolver( state.Binder, newArgs, signature, codeContext ), Value.Template.Targets, selfRestrict, Value.Template.Name, NarrowingLevel.None, Value.Template.IsBinaryOperator ? PythonNarrowing.BinaryOperator : NarrowingLevel.All, out target ); return BindingHelpers.CheckLightThrow(call, res, target); }); }
public FunctionBinderHelper(DynamicMetaObjectBinder call, MetaTotemFunction function, Expression codeContext, DynamicMetaObject[] args) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "TotemFunction Invoke " + function.Value.FunctionCompatibility + " w/ " + args.Length + " args"); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "TotemFunction"); _call = call; _func = function; _args = args; _originalArgs = args; _temps = new List<ParameterExpression>(); _codeContext = codeContext; // Remove the passed in instance argument if present int instanceIndex = Signature.IndexOf(ArgumentType.Instance); if (instanceIndex > -1) _args = ArrayUtils.RemoveAt(_args, instanceIndex); }
private DynamicMetaObject/*!*/ InvokeWorker(DynamicMetaObjectBinder/*!*/ call, DynamicMetaObject/*!*/[]/*!*/ args, Expression/*!*/ codeContext) { if (this.NeedsDeferral()) { return call.Defer(ArrayUtils.Insert(this, args)); } for (int i = 0; i < args.Length; i++) { if (args[i].NeedsDeferral()) { return call.Defer(ArrayUtils.Insert(this, args)); } } if (IsStandardDotNetType(call)) { return MakeStandardDotNetTypeCall(call, codeContext, args); } return MakePythonTypeCall(call, codeContext, args); }
internal static DynamicMetaObject/*!*/ FilterShowCls(Expression/*!*/ codeContext, DynamicMetaObjectBinder/*!*/ action, DynamicMetaObject/*!*/ res, Expression/*!*/ failure) { if (action is IPythonSite) { return new DynamicMetaObject( Ast.Condition( Ast.Call( typeof(PythonOps).GetMethod("IsClsVisible"), codeContext ), AstUtils.Convert(res.Expression, typeof(object)), AstUtils.Convert(failure, typeof(object)) ), res.Restrictions ); } return res; }
private DynamicMetaObject/*!*/ InvokeWorker(DynamicMetaObjectBinder/*!*/ call, DynamicMetaObject/*!*/[]/*!*/ args, Expression/*!*/ codeContext) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "Type Invoke " + Value.UnderlyingSystemType.FullName + args.Length); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "Type Invoke"); if (this.NeedsDeferral()) { return call.Defer(ArrayUtils.Insert(this, args)); } for (int i = 0; i < args.Length; i++) { if (args[i].NeedsDeferral()) { return call.Defer(ArrayUtils.Insert(this, args)); } } if (IsStandardDotNetType(call)) { return MakeStandardDotNetTypeCall(call, codeContext, args); } return MakePythonTypeCall(call, codeContext, args); }
public Expression Dynamic(DynamicMetaObjectBinder binder, Type retType, Expression[] args) { Assert.NotNull(binder, retType, args); Assert.NotNullItems(args); switch(args.Length) { case 1: return Dynamic(binder, retType, args[0]); case 2: return Dynamic(binder, retType, args[0], args[1]); case 3: return Dynamic(binder, retType, args[0], args[1], args[2]); case 4: return Dynamic(binder, retType, args[0], args[1], args[2], args[3]); } if(retType == typeof(object)) { return new TotemDynamicExpressionN(binder, this, args); } return ReduceDynamic(binder, retType, args); }
internal static DynamicMetaObject/*!*/ FilterShowCls(Expression/*!*/ codeContext, DynamicMetaObjectBinder/*!*/ action, DynamicMetaObject/*!*/ res, Expression/*!*/ failure) { if (action is IPythonSite) { Type resType = BindingHelpers.GetCompatibleType(res.Expression.Type, failure.Type); return new DynamicMetaObject( Ast.Condition( Ast.Call( typeof(PythonOps).GetMethod("IsClsVisible"), codeContext ), AstUtils.Convert(res.Expression, resType), AstUtils.Convert(failure, resType) ), res.Restrictions ); } return res; }
private DynamicMetaObject/*!*/ InvokeWorker(DynamicMetaObjectBinder/*!*/ call, Expression/*!*/ codeContext, DynamicMetaObject/*!*/[]/*!*/ args) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "BuiltinFunc Invoke " + Value.DeclaringType.FullName + "." + Value.Name + " with " + args.Length + " args " + Value.IsUnbound); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "BuiltinFunction " + Value.Targets.Count + ", " + Value.Targets[0].GetParameters().Length); PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "BuiltinFunction " + BindingHelpers.GetCallSignature(call)); if (this.NeedsDeferral()) { return call.Defer(ArrayUtils.Insert(this, args)); } for (int i = 0; i < args.Length; i++) { if (args[i].NeedsDeferral()) { return call.Defer(ArrayUtils.Insert(this, args)); } } if (Value.IsUnbound) { return MakeSelflessCall(call, codeContext, args); } else { return MakeSelfCall(call, codeContext, args); } }
/// <summary> /// Helper method for generating a MetaObject which calls a /// specific method on Dynamic that returns a result /// </summary> private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback) { return(CallMethodWithResult(methodName, binder, args, fallback, null)); }
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 static DynamicMetaObject/*!*/ MakeBinaryOperatorResult(DynamicMetaObject/*!*/[]/*!*/ types, DynamicMetaObjectBinder/*!*/ operation, PythonOperationKind op, SlotOrFunction/*!*/ fCand, SlotOrFunction/*!*/ rCand, PythonTypeSlot fSlot, PythonTypeSlot rSlot, DynamicMetaObject errorSuggestion) { Assert.NotNull(operation, fCand, rCand); SlotOrFunction fTarget, rTarget; PythonContext state = PythonContext.GetPythonContext(operation); ConditionalBuilder bodyBuilder = new ConditionalBuilder(operation); if ((op & PythonOperationKind.InPlace) != 0) { // in place operator, see if there's a specific method that handles it. SlotOrFunction function = SlotOrFunction.GetSlotOrFunction(PythonContext.GetPythonContext(operation), Symbols.OperatorToSymbol(op), types); // we don't do a coerce for in place operators if the lhs implements __iop__ if (!MakeOneCompareGeneric(function, false, types, MakeCompareReturn, bodyBuilder, typeof(object))) { // the method handles it and always returns a useful value. return bodyBuilder.GetMetaObject(types); } } if (!SlotOrFunction.GetCombinedTargets(fCand, rCand, out fTarget, out rTarget) && fSlot == null && rSlot == null && !ShouldCoerce(state, op, types[0], types[1], false) && !ShouldCoerce(state, op, types[1], types[0], false) && bodyBuilder.NoConditions) { return MakeRuleForNoMatch(operation, op, errorSuggestion, types); } if (ShouldCoerce(state, op, types[0], types[1], false) && (op != PythonOperationKind.Mod || !MetaPythonObject.GetPythonType(types[0]).IsSubclassOf(TypeCache.String))) { // need to try __coerce__ first. DoCoerce(state, bodyBuilder, op, types, false); } if (MakeOneTarget(PythonContext.GetPythonContext(operation), fTarget, fSlot, bodyBuilder, false, types)) { if (ShouldCoerce(state, op, types[1], types[0], false)) { // need to try __coerce__ on the reverse first DoCoerce(state, bodyBuilder, op, new DynamicMetaObject[] { types[1], types[0] }, true); } if (rSlot != null) { MakeSlotCall(PythonContext.GetPythonContext(operation), types, bodyBuilder, rSlot, true); bodyBuilder.FinishCondition(MakeBinaryThrow(operation, op, types).Expression, typeof(object)); } else if (MakeOneTarget(PythonContext.GetPythonContext(operation), rTarget, rSlot, bodyBuilder, false, types)) { // need to fallback to throwing or coercion bodyBuilder.FinishCondition(MakeBinaryThrow(operation, op, types).Expression, typeof(object)); } } return bodyBuilder.GetMetaObject(types); }
private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, DynamicMetaObject fallbackResult, Fallback fallbackInvoke) { // // Build a new expression like: // { // object result; // TryGetMember(payload, out result) ? fallbackInvoke(result) : fallbackResult // } // { // Option<object> result; // result = TryGetMember(payload, out result) // result.HasValue ? fallbackInvoke(result.Value) : fallbackResult // } // var result = Expression.Parameter(typeof(Option <object>), null); var callArgs = new Expression[] { Expression.Convert(Expression, typeof(T)), Constant(binder) }.Concat(args); var resultDmo = new DynamicMetaObject(Expression.MakeMemberAccess( result, typeof(Option <object>).GetProperty("Value") ), BindingRestrictions.Empty); // Need to add a conversion if calling TryConvert if (binder.ReturnType != typeof(object)) { Debug.Assert(binder is ConvertBinder && fallbackInvoke == null); var convert = Expression.Convert(resultDmo.Expression, binder.ReturnType); // will always be a cast or unbox Debug.Assert(convert.Method == null); resultDmo = new DynamicMetaObject(convert, resultDmo.Restrictions); } if (fallbackInvoke != null) { resultDmo = fallbackInvoke(resultDmo); } var callDynamic = new DynamicMetaObject( Expression.Block( new[] { result }, Expression.Assign( result, Expression.Invoke( Expression.MakeMemberAccess( Expression.Constant(_runtime), typeof(DynamicObjectRuntime <T>).GetProperty(methodName)), callArgs )), Expression.Condition( Expression.MakeMemberAccess( result, typeof(Option <object>).GetProperty("HasValue") ), resultDmo.Expression, fallbackResult.Expression, binder.ReturnType ) ), GetRestrictions().Merge(resultDmo.Restrictions).Merge(fallbackResult.Restrictions) ); return(callDynamic); }
internal static BuiltinFunction.BindingResult CheckLightThrow(DynamicMetaObjectBinder call, DynamicMetaObject res, BindingTarget target) { return(new BuiltinFunction.BindingResult(target, CheckLightThrowMO(call, res, target))); }
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 static DynamicMetaObject Bind( DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable <DynamicMetaObject> args, IEnumerable <CSharpArgumentInfo> arginfos, DynamicMetaObject onBindingError) { List <Expression> parameters = new List <Expression>(); BindingRestrictions restrictions = BindingRestrictions.Empty; ICSharpInvokeOrInvokeMemberBinder callPayload = action as ICSharpInvokeOrInvokeMemberBinder; ParameterExpression tempForIncrement = null; IEnumerator <CSharpArgumentInfo> arginfosEnum = arginfos == null ? null : arginfos.GetEnumerator(); int index = 0; foreach (DynamicMetaObject o in args) { // Our contract with the DLR is such that we will not enter a bind unless we have // values for the meta-objects involved. if (!o.HasValue) { Debug.Assert(false, "The runtime binder is being asked to bind a metaobject without a value"); throw Error.InternalCompilerError(); } CSharpArgumentInfo info = null; if (arginfosEnum != null && arginfosEnum.MoveNext()) { info = arginfosEnum.Current; } if (index == 0 && IsIncrementOrDecrementActionOnLocal(action)) { // We have an inc or a dec operation. Insert the temp local instead. // // We need to do this because for value types, the object will come // in boxed, and we'd need to unbox it to get the original type in order // to increment. The only way to do that is to create a new temporary. tempForIncrement = Expression.Variable(o.Value != null ? o.Value.GetType() : typeof(object), "t0"); parameters.Add(tempForIncrement); } else { parameters.Add(o.Expression); } BindingRestrictions r = DeduceArgumentRestriction(index, callPayload, o, info); restrictions = restrictions.Merge(r); // Here we check the argument info. If the argument info shows that the current argument // is a literal constant, then we also add an instance restriction on the value of // the constant. if (info != null && info.LiteralConstant) { if ((o.Value is float && float.IsNaN((float)o.Value)) || o.Value is double && double.IsNaN((double)o.Value)) { // We cannot create an equality restriction for NaN, because equality is implemented // in such a way that NaN != NaN and the rule we make would be unsatisfiable. } else { Expression e = Expression.Equal(o.Expression, Expression.Constant(o.Value, o.Expression.Type)); r = BindingRestrictions.GetExpressionRestriction(e); restrictions = restrictions.Merge(r); } } ++index; } // Get the bound expression. try { DynamicMetaObject deferredBinding; Expression expression = binder.Bind(action, parameters, args.ToArray(), out deferredBinding); if (deferredBinding != null) { expression = ConvertResult(deferredBinding.Expression, action); restrictions = deferredBinding.Restrictions.Merge(restrictions); return(new DynamicMetaObject(expression, restrictions)); } if (tempForIncrement != null) { // If we have a ++ or -- payload, we need to do some temp rewriting. // We rewrite to the following: // // temp = (type)o; // temp++; // o = temp; // return o; DynamicMetaObject arg0 = Enumerable.First(args); Expression assignTemp = Expression.Assign( tempForIncrement, Expression.Convert(arg0.Expression, arg0.Value.GetType())); Expression assignResult = Expression.Assign( arg0.Expression, Expression.Convert(tempForIncrement, arg0.Expression.Type)); List <Expression> expressions = new List <Expression>(); expressions.Add(assignTemp); expressions.Add(expression); expressions.Add(assignResult); expression = Expression.Block(new ParameterExpression[] { tempForIncrement }, expressions); } expression = ConvertResult(expression, action); return(new DynamicMetaObject(expression, restrictions)); } catch (RuntimeBinderException e) { if (onBindingError != null) { return(onBindingError); } return(new DynamicMetaObject( Expression.Throw( Expression.New( typeof(RuntimeBinderException).GetConstructor(new Type[] { typeof(string) }), Expression.Constant(e.Message) ), GetTypeForErrorMetaObject(action, args.FirstOrDefault()) ), restrictions )); } }
private DynamicMetaObject /*!*/ MakeDynamicMemberAccess(DynamicMetaObjectBinder /*!*/ member, string /*!*/ name, MemberAccess access, DynamicMetaObject /*!*/[] /*!*/ args) { DynamicMetaObject self = Restrict(typeof(OldInstance)); Expression target; ParameterExpression tmp = Ast.Variable(typeof(object), "result"); switch (access) { case MemberAccess.Invoke: target = Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Expression.Not( Expression.TypeIs( Expression.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceTryGetBoundCustomMember)), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name) ) ), typeof(OperationFailed) ) ), ((InvokeMemberBinder)member).FallbackInvoke(new DynamicMetaObject(tmp, BindingRestrictions.Empty), args, null).Expression, AstUtils.Convert( ((InvokeMemberBinder)member).FallbackInvokeMember(this, args).Expression, typeof(object) ) ) ); break; case MemberAccess.Get: target = Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Expression.Not( Expression.TypeIs( Expression.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceTryGetBoundCustomMember)), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name) ) ), typeof(OperationFailed) ) ), tmp, AstUtils.Convert( FallbackGet(member, args), typeof(object) ) ) ); break; case MemberAccess.Set: target = Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceSetCustomMember)), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name), AstUtils.Convert(args[1].Expression, typeof(object)) ); break; case MemberAccess.Delete: target = Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceDeleteCustomMember)), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name) ); break; default: throw new InvalidOperationException(); } return(new DynamicMetaObject( target, self.Restrictions.Merge(BindingRestrictions.Combine(args)) )); }
public virtual MSAst.Expression/*!*/ Dynamic(DynamicMetaObjectBinder/*!*/ binder, Type/*!*/ retType, MSAst.Expression/*!*/ arg0, MSAst.Expression/*!*/ arg1) { return MSAst.Expression.Dynamic(binder, retType, arg0, arg1); }
internal static DynamicMetaObject TranslateArguments(DynamicMetaObjectBinder call, Expression codeContext, DynamicMetaObject function, DynamicMetaObject /*!*/[] args, bool hasSelf, string name) { if (hasSelf) { args = ArrayUtils.RemoveFirst(args); } CallSignature sig = BindingHelpers.GetCallSignature(call); if (sig.HasDictionaryArgument()) { int index = sig.IndexOf(ArgumentType.Dictionary); DynamicMetaObject dict = args[index]; if (!(dict.Value is IDictionary) && dict.Value != null) { // The DefaultBinder only handles types that implement IDictionary. Here we have an // arbitrary user-defined mapping type. We'll convert it into a PythonDictionary // and then have an embedded dynamic site pass that dictionary through to the default // binder. DynamicMetaObject[] dynamicArgs = ArrayUtils.Insert(function, args); dynamicArgs[index + 1] = new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.UserMappingToPythonDictionary)), codeContext, args[index].Expression, AstUtils.Constant(name) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType()), PythonOps.UserMappingToPythonDictionary(PythonContext.GetPythonContext(call).SharedContext, dict.Value, name) ); if (call is IPythonSite) { dynamicArgs = ArrayUtils.Insert( new DynamicMetaObject(codeContext, BindingRestrictions.Empty), dynamicArgs ); } return(new DynamicMetaObject( DynamicExpression.Dynamic( call, typeof(object), DynamicUtils.GetExpressions(dynamicArgs) ), BindingRestrictions.Combine(dynamicArgs).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType())) )); } } if (sig.HasListArgument()) { int index = sig.IndexOf(ArgumentType.List); DynamicMetaObject str = args[index]; // TODO: ANything w/ __iter__ that's not an IList<object> if (!(str.Value is IList <object>) && str.Value is IEnumerable) { // The DefaultBinder only handles types that implement IList<object>. Here we have a // string. We'll convert it into a tuple // and then have an embedded dynamic site pass that tuple through to the default // binder. DynamicMetaObject[] dynamicArgs = ArrayUtils.Insert(function, args); dynamicArgs[index + 1] = new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.MakeTupleFromSequence)), Expression.Convert(args[index].Expression, typeof(object)) ), BindingRestrictions.Empty ); if (call is IPythonSite) { dynamicArgs = ArrayUtils.Insert( new DynamicMetaObject(codeContext, BindingRestrictions.Empty), dynamicArgs ); } return(new DynamicMetaObject( DynamicExpression.Dynamic( call, typeof(object), DynamicUtils.GetExpressions(dynamicArgs) ), function.Restrictions.Merge( BindingRestrictions.Combine(args).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(str.Expression, str.GetLimitType())) ) )); } } return(null); }
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> /// Helper method for generating a MetaObject which calls a /// specific method on Dynamic that returns a result /// </summary> private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback, Fallback fallbackInvoke) { // // First, call fallback to do default binding // This produces either an error or a call to a .NET member // DynamicMetaObject fallbackResult = fallback(null); // // Build a new expression like: // { // object result; // TryGetMember(payload, out result) ? fallbackInvoke(result) : fallbackResult // } // var result = Expression.Parameter(typeof(object), null); var callArgs = new Expression[args.Length + 2]; Array.Copy(args, 0, callArgs, 1, args.Length); callArgs[0] = Constant(binder); callArgs[callArgs.Length - 1] = result; var resultMO = new DynamicMetaObject(result, BindingRestrictions.Empty); // Need to add a conversion if calling TryConvert if (binder.ReturnType != typeof(object)) { Debug.Assert(binder is ConvertBinder && fallbackInvoke == null); var convert = Expression.Convert(resultMO.Expression, binder.ReturnType); // will always be a cast or unbox Debug.Assert(convert.Method == null); resultMO = new DynamicMetaObject(convert, resultMO.Restrictions); } if (fallbackInvoke != null) { resultMO = fallbackInvoke(resultMO); } var callDynamic = new DynamicMetaObject( Expression.Block( new[] { result }, Expression.Condition( Expression.Call( GetLimitedSelf(), typeof(DynamicObject).GetMethod(methodName), callArgs ), resultMO.Expression, fallbackResult.Expression, binder.ReturnType ) ), GetRestrictions().Merge(resultMO.Restrictions).Merge(fallbackResult.Restrictions) ); // // Now, call fallback again using our new MO as the error // When we do this, one of two things can happen: // 1. Binding will succeed, and it will ignore our call to // the dynamic method, OR // 2. Binding will fail, and it will use the MO we created // above. // return(fallback(callDynamic)); }
public ConditionalBuilder(DynamicMetaObjectBinder /*!*/ action) { _action = action; }
public virtual MSAst.Expression /*!*/ Dynamic(DynamicMetaObjectBinder /*!*/ binder, Type /*!*/ retType, MSAst.Expression /*!*/ arg0) { return(MSAst.Expression.Dynamic(binder, retType, arg0)); }
private DynamicMetaObject/*!*/ InvokeWorker(DynamicMetaObjectBinder/*!*/ invoke, Expression/*!*/ codeContext, DynamicMetaObject/*!*/[] args) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass Invoke"); DynamicMetaObject self = Restrict(typeof(OldInstance)); Expression[] exprArgs = new Expression[args.Length + 1]; for (int i = 0; i < args.Length; i++) { exprArgs[i + 1] = args[i].Expression; } ParameterExpression tmp = Ast.Variable(typeof(object), "callFunc"); exprArgs[0] = tmp; return new DynamicMetaObject( // we could get better throughput w/ a more specific rule against our current custom old class but // this favors less code generation. Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.Call( typeof(PythonOps).GetMethod("OldInstanceTryGetBoundCustomMember"), codeContext, self.Expression, AstUtils.Constant("__call__"), tmp ), Ast.Block( Utils.Try( Ast.Call(typeof(PythonOps).GetMethod("FunctionPushFrameCodeContext"), codeContext), Ast.Assign( tmp, Ast.Dynamic( PythonContext.GetPythonContext(invoke).Invoke( BindingHelpers.GetCallSignature(invoke) ), typeof(object), ArrayUtils.Insert(codeContext, exprArgs) ) ) ).Finally( Ast.Call(typeof(PythonOps).GetMethod("FunctionPopFrame")) ), tmp ), Utils.Convert( BindingHelpers.InvokeFallback(invoke, codeContext, this, args).Expression, typeof(object) ) ) ), self.Restrictions.Merge(BindingRestrictions.Combine(args)) ); }
private DynamicMetaObject /*!*/ MakeMemberAccess(DynamicMetaObjectBinder /*!*/ member, string name, MemberAccess access, params DynamicMetaObject /*!*/[] /*!*/ args) { DynamicMetaObject self = Restrict(typeof(OldInstance)); CustomInstanceDictionaryStorage dict; int key = GetCustomStorageSlot(name, out dict); if (key == -1) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldInstance " + access + " NoOptimized"); return(MakeDynamicMemberAccess(member, name, access, args)); } ParameterExpression tmp = Ast.Variable(typeof(object), "dict"); Expression target; ValidationInfo test = new ValidationInfo( Ast.NotEqual( Ast.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceGetOptimizedDictionary)), self.Expression, AstUtils.Constant(dict.KeyVersion) ) ), AstUtils.Constant(null) ) ); PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldInstance " + access + " Optimized"); switch (access) { case MemberAccess.Invoke: ParameterExpression value = Ast.Variable(typeof(object), "value"); target = Ast.Block( new[] { value }, Ast.Condition( Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.TryOldInstanceDictionaryGetValueHelper)), tmp, Ast.Constant(key), AstUtils.Convert(Expression, typeof(object)), value ), AstUtils.Convert( ((InvokeMemberBinder)member).FallbackInvoke(new DynamicMetaObject(value, BindingRestrictions.Empty), args, null).Expression, typeof(object) ), AstUtils.Convert( ((InvokeMemberBinder)member).FallbackInvokeMember(self, args).Expression, typeof(object) ) ) ); break; case MemberAccess.Get: // BUG: There's a missing Fallback path here that's always been present even // in the version that used rules. target = Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceDictionaryGetValueHelper)), tmp, AstUtils.Constant(key), AstUtils.Convert(Expression, typeof(object)) ); break; case MemberAccess.Set: target = Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceDictionarySetExtraValue)), tmp, AstUtils.Constant(key), AstUtils.Convert(args[1].Expression, typeof(object)) ); break; case MemberAccess.Delete: target = Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceDeleteCustomMember)), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), AstUtils.Convert(Expression, typeof(OldInstance)), AstUtils.Constant(name) ); break; default: throw new InvalidOperationException(); } return(BindingHelpers.AddDynamicTestAndDefer( member, new DynamicMetaObject( target, BindingRestrictions.Combine(args).Merge(self.Restrictions) ), args, test, tmp )); }
private DynamicMetaObject/*!*/ MakeConvertToIEnumerable(DynamicMetaObjectBinder/*!*/ conversion, Type toType, Type genericType) { ParameterExpression tmp = Ast.Variable(toType, "res"); DynamicMetaObject self = Restrict(typeof(OldInstance)); return new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.NotEqual( Ast.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod("OldInstanceConvertToIEnumerableOfTNonThrowing").MakeGenericMethod(genericType), AstUtils.Constant(PythonContext.GetPythonContext(conversion).SharedContext), self.Expression ) ), AstUtils.Constant(null) ), tmp, AstUtils.Convert( AstUtils.Convert( FallbackConvert(conversion).Expression, typeof(object) ), toType ) ) ), self.Restrictions ); }
internal static DynamicMetaObject /*!*/ AddDynamicTestAndDefer(DynamicMetaObjectBinder /*!*/ operation, DynamicMetaObject /*!*/ res, DynamicMetaObject /*!*/[] args, ValidationInfo typeTest, params ParameterExpression[] temps) { return(AddDynamicTestAndDefer(operation, res, args, typeTest, null, temps)); }
private static BinaryExpression/*!*/ MakeOneConvert(DynamicMetaObjectBinder/*!*/ conversion, DynamicMetaObject/*!*/ self, string name, ParameterExpression/*!*/ tmp) { return Ast.NotEqual( Ast.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod("OldInstanceConvertNonThrowing"), AstUtils.Constant(PythonContext.GetPythonContext(conversion).SharedContext), self.Expression, AstUtils.Constant(name) ) ), AstUtils.Constant(null) ); }
internal static DynamicMetaObject /*!*/ FilterShowCls(DynamicMetaObject /*!*/ codeContext, DynamicMetaObjectBinder /*!*/ action, DynamicMetaObject /*!*/ res, Expression /*!*/ failure) { if (action is IPythonSite) { return(new DynamicMetaObject( Ast.Condition( Ast.Call( typeof(PythonOps).GetMethod("IsClsVisible"), codeContext.Expression ), AstUtils.Convert(res.Expression, typeof(object)), AstUtils.Convert(failure, typeof(object)) ), res.Restrictions )); } return(res); }
private DynamicMetaObject/*!*/ MakeMemberAccess(DynamicMetaObjectBinder/*!*/ member, string name, MemberAccess access, params DynamicMetaObject/*!*/[]/*!*/ args) { DynamicMetaObject self = Restrict(typeof(OldInstance)); CustomOldClassDictionaryStorage dict; int key = GetCustomStorageSlot(name, out dict); if (key == -1) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldInstance " + access + " NoOptimized"); return MakeDynamicMemberAccess(member, name, access, args); } ParameterExpression tmp = Ast.Variable(typeof(object), "dict"); Expression target; ValidationInfo test = new ValidationInfo( Ast.NotEqual( Ast.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod("OldInstanceGetOptimizedDictionary"), self.Expression, AstUtils.Constant(dict.KeyVersion) ) ), AstUtils.Constant(null) ) ); PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldInstance " + access + " Optimized"); switch (access) { case MemberAccess.Invoke: ParameterExpression value = Ast.Variable(typeof(object), "value"); target = Ast.Block( new[] { value }, Ast.Condition( Ast.Call( typeof(PythonOps).GetMethod("TryOldInstanceDictionaryGetValueHelper"), tmp, Ast.Constant(key), AstUtils.Convert(Expression, typeof(object)), value ), AstUtils.Convert( ((InvokeMemberBinder)member).FallbackInvoke(new DynamicMetaObject(value, BindingRestrictions.Empty), args, null).Expression, typeof(object) ), AstUtils.Convert( ((InvokeMemberBinder)member).FallbackInvokeMember(self, args).Expression, typeof(object) ) ) ); break; case MemberAccess.Get: // BUG: There's a missing Fallback path here that's always been present even // in the version that used rules. target = Ast.Call( typeof(PythonOps).GetMethod("OldInstanceDictionaryGetValueHelper"), tmp, AstUtils.Constant(key), AstUtils.Convert(Expression, typeof(object)) ); break; case MemberAccess.Set: target = Ast.Call( typeof(PythonOps).GetMethod("OldInstanceDictionarySetExtraValue"), tmp, AstUtils.Constant(key), AstUtils.Convert(args[1].Expression, typeof(object)) ); break; case MemberAccess.Delete: target = Ast.Call( typeof(PythonOps).GetMethod("OldInstanceDeleteCustomMember"), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), AstUtils.Convert(Expression, typeof(OldInstance)), AstUtils.Constant(name) ); break; default: throw new InvalidOperationException(); } return BindingHelpers.AddDynamicTestAndDefer( member, new DynamicMetaObject( target, BindingRestrictions.Combine(args).Merge(self.Restrictions) ), args, test, tmp ); }
private static DynamicMetaObject/*!*/ MakeSimpleOperation(DynamicMetaObject/*!*/[]/*!*/ types, DynamicMetaObjectBinder/*!*/ binder, PythonOperationKind operation, DynamicMetaObject errorSuggestion) { RestrictTypes(types); SlotOrFunction fbinder; SlotOrFunction rbinder; PythonTypeSlot fSlot; PythonTypeSlot rSlot; GetOperatorMethods(types, operation, PythonContext.GetPythonContext(binder), out fbinder, out rbinder, out fSlot, out rSlot); return MakeBinaryOperatorResult(types, binder, operation, fbinder, rbinder, fSlot, rSlot, errorSuggestion); }
private static Expression FallbackGet(DynamicMetaObjectBinder member, DynamicMetaObject[] args) { GetMemberBinder sa = member as GetMemberBinder; if (sa != null) { return sa.FallbackGetMember(args[0]).Expression; } return ((PythonGetMemberBinder)member).Fallback(args[0], PythonContext.GetCodeContextMO(member)).Expression; }
public virtual MSAst.Expression/*!*/ Dynamic(DynamicMetaObjectBinder/*!*/ binder, Type/*!*/ retType, IList<MSAst.Expression/*!*/>/*!*/ args) { Assert.NotNull(binder, retType, args); Assert.NotNullItems(args); return MSAst.Expression.Dynamic(binder, retType, args); }
static DynamicMetaObject \u200C([In] DynamicMetaObjectBinder obj0, [In] DynamicMetaObject obj1, [In] DynamicMetaObject[] obj2) { // ISSUE: unable to decompile the method. }
/// <summary> /// Helper for generating the call to a builtin function. This is used for calls from built-in method /// descriptors and built-in functions w/ and w/o a bound instance. /// /// This provides all sorts of common checks on top of the call while the caller provides a delegate /// to do the actual call. The common checks include: /// check for generic-only methods /// reversed operator support /// transforming arguments so the default binder can understand them (currently user defined mapping types to PythonDictionary) /// returning NotImplemented from binary operators /// Warning when calling certain built-in functions /// /// </summary> /// <param name="call">The call binder we're doing the call for</param> /// <param name="codeContext">An expression which points to the code context</param> /// <param name="function">the meta object for the built in function</param> /// <param name="hasSelf">true if we're calling with an instance</param> /// <param name="args">The arguments being passed to the function</param> /// <param name="functionRestriction">A restriction for the built-in function, method desc, etc...</param> /// <param name="bind">A delegate to perform the actual call to the method.</param> internal DynamicMetaObject /*!*/ MakeBuiltinFunctionCall(DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext, DynamicMetaObject /*!*/ function, DynamicMetaObject /*!*/[] args, bool hasSelf, BindingRestrictions /*!*/ functionRestriction, Func <DynamicMetaObject /*!*/[] /*!*/, BindingResult /*!*/> bind) { DynamicMetaObject res = null; // if we have a user defined operator for **args then transform it into a PythonDictionary DynamicMetaObject translated = TranslateArguments(call, codeContext, new DynamicMetaObject(function.Expression, functionRestriction, function.Value), args, hasSelf, Name); if (translated != null) { return(translated); } // swap the arguments if we have a reversed operator if (IsReversedOperator) { ArrayUtils.SwapLastTwo(args); } // do the appropriate calling logic BindingResult result = bind(args); // validate the result BindingTarget target = result.Target; res = result.MetaObject; if (target.Overload != null && target.Overload.IsProtected) { // report an error when calling a protected member res = new DynamicMetaObject( BindingHelpers.TypeErrorForProtectedMember( target.Overload.DeclaringType, target.Overload.Name ), res.Restrictions ); } else if (IsBinaryOperator && args.Length == 2 && IsThrowException(res.Expression)) { // Binary Operators return NotImplemented on failure. res = new DynamicMetaObject( Ast.Property(null, typeof(PythonOps), "NotImplemented"), res.Restrictions ); } else if (target.Overload != null) { // Add profiling information for this builtin function, if applicable IPythonSite pythonSite = (call as IPythonSite); if (pythonSite != null) { var pc = pythonSite.Context; var po = pc.Options as PythonOptions; if (po != null && po.EnableProfiler) { Profiler profiler = Profiler.GetProfiler(pc); res = new DynamicMetaObject( profiler.AddProfiling(res.Expression, target.Overload.ReflectionInfo), res.Restrictions ); } } } // add any warnings that are applicable for calling this function WarningInfo info; if (target.Overload != null && BindingWarnings.ShouldWarn(PythonContext.GetPythonContext(call), target.Overload, out info)) { res = info.AddWarning(codeContext, res); } // finally add the restrictions for the built-in function and return the result. res = new DynamicMetaObject( res.Expression, functionRestriction.Merge(res.Restrictions) ); // The function can return something typed to boolean or int. // If that happens, we need to apply Python's boxing rules. if (res.Expression.Type.IsValueType()) { res = BindingHelpers.AddPythonBoxing(res); } else if (res.Expression.Type == typeof(void)) { res = new DynamicMetaObject( Expression.Block( res.Expression, Expression.Constant(null) ), res.Restrictions ); } return(res); }
public BinderMappingInfo(DynamicMetaObjectBinder binder, IList<ParameterMappingInfo> mappingInfo) { Binder = binder; MappingInfo = mappingInfo; }
internal DynamicMetaObject /*!*/ CreateMetaObject(DynamicMetaObjectBinder /*!*/ action) { return(CreateMetaObject(action, action.ReturnType)); }
public BinderMappingInfo(DynamicMetaObjectBinder binder, params ParameterMappingInfo[] mappingInfos) : this(binder, (IList<ParameterMappingInfo>)mappingInfos) { }
public DynamicMetaObject ConvertWorker(DynamicMetaObjectBinder binder, Type type, Type retType, ConversionResultKind kind) { if (!type.IsEnum) { switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: return MakeConvertToBool(binder); case TypeCode.Int32: return MakeConvertToCommon(binder, type, retType, "__int__"); case TypeCode.Double: return MakeConvertToCommon(binder, type, retType, "__float__"); case TypeCode.String: return MakeConvertToCommon(binder, type, retType, "__str__"); case TypeCode.Object: if (type == typeof(BigInteger)) { return MakeConvertToCommon(binder, type, retType, "__long__"); } else if (type == typeof(Complex64)) { return MakeConvertToCommon(binder, type, retType, "__complex__"); } else if (type == typeof(IEnumerable)) { return MakeConvertToIEnumerable(binder); } else if (type == typeof(IEnumerator)) { return MakeConvertToIEnumerator(binder); } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { return MakeConvertToIEnumerable(binder, type, type.GetGenericArguments()[0]); } else if (type.IsSubclassOf(typeof(Delegate))) { return MakeDelegateTarget(binder, type, Restrict(typeof(OldInstance))); } break; } } return FallbackConvert(binder); }
internal static DynamicMetaObject FallbackWorker(PythonContext context, DynamicMetaObject /*!*/ self, DynamicMetaObject /*!*/ codeContext, string name, GetMemberOptions options, DynamicMetaObjectBinder action, DynamicMetaObject errorSuggestion) { if (self.NeedsDeferral()) { return(action.Defer(self)); } PythonOverloadResolverFactory resolverFactory = new PythonOverloadResolverFactory(context.Binder, codeContext.Expression); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "FallbackGet"); 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 = PythonContext.GetPythonContext(action).Binder.GetMember( name, self, resolverFactory, isNoThrow, errorSuggestion ); Expression failure = GetFailureExpression(limitType, self, name, isNoThrow, action); return(BindingHelpers.FilterShowCls(codeContext, action, baseRes, failure)); } } var res = context.Binder.GetMember(name, self, resolverFactory, isNoThrow, errorSuggestion); if (res is ErrorMetaObject) { // see if we can bind to any extension methods... var codeCtx = (CodeContext)codeContext.Value; var extMethods = codeCtx.ModuleContext.ExtensionMethods; if (extMethods != null) { // try again w/ the extension method binder res = extMethods.GetBinder(context).GetMember(name, self, resolverFactory, isNoThrow, errorSuggestion); } // and add any restrictions (we need an empty restriction even if it's an error so later adds work) res = new DynamicMetaObject( res.Expression, res.Restrictions.Merge(extMethods.GetRestriction(codeContext.Expression)) ); } // 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.IsValueType()) { res = new DynamicMetaObject( AstUtils.Convert(res.Expression, typeof(object)), res.Restrictions ); } return(res); }
private DynamicMetaObject/*!*/ MakeConvertToIEnumerable(DynamicMetaObjectBinder/*!*/ conversion) { ParameterExpression tmp = Ast.Variable(typeof(IEnumerable), "res"); DynamicMetaObject self = Restrict(typeof(OldInstance)); return new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.NotEqual( Ast.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod("OldInstanceConvertToIEnumerableNonThrowing"), AstUtils.Constant(PythonContext.GetPythonContext(conversion).SharedContext), self.Expression ) ), AstUtils.Constant(null) ), tmp, AstUtils.Convert( AstUtils.Convert( // first to object (incase it's a throw), then to IEnumerable FallbackConvert(conversion).Expression, typeof(object) ), typeof(IEnumerable) ) ) ), self.Restrictions ); }
private static Expression /*!*/ GetFailureExpression(Type /*!*/ limitType, DynamicMetaObject self, string name, bool isNoThrow, DynamicMetaObjectBinder action) { return(isNoThrow ? Ast.Field(null, typeof(OperationFailed).GetField("Value")) : DefaultBinder.MakeError( PythonContext.GetPythonContext(action).Binder.MakeMissingMemberError( limitType, self, name ), typeof(object) ).Expression); }
private DynamicMetaObject/*!*/ MakeConvertToCommon(DynamicMetaObjectBinder/*!*/ conversion, Type toType, Type retType, string name) { // TODO: support trys ParameterExpression tmp = Ast.Variable(typeof(object), "convertResult"); DynamicMetaObject self = Restrict(typeof(OldInstance)); return new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( MakeOneConvert(conversion, self, name, tmp), Expression.Convert( tmp, retType ), FallbackConvert(conversion).Expression ) ), self.Restrictions ); }
/// <summary> /// Creating a Python type involves calling __new__ and __init__. We resolve them /// and generate calls to either the builtin funcions directly or embed sites which /// call the slots at runtime. /// </summary> private DynamicMetaObject /*!*/ MakePythonTypeCall(DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext, DynamicMetaObject /*!*/[] /*!*/ args) { ValidationInfo valInfo = MakeVersionCheck(); DynamicMetaObject self = new RestrictedMetaObject( AstUtils.Convert(Expression, LimitType), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(Expression, LimitType), Value ); CallSignature sig = BindingHelpers.GetCallSignature(call); ArgumentValues ai = new ArgumentValues(sig, self, args); NewAdapter newAdapter; InitAdapter initAdapter; if (TooManyArgsForDefaultNew(call, args)) { return(MakeIncorrectArgumentsForCallError(call, ai, valInfo)); } else if (Value.UnderlyingSystemType.IsGenericTypeDefinition) { return(MakeGenericTypeDefinitionError(call, ai, valInfo)); } else if (Value.HasAbstractMethods(PythonContext.GetPythonContext(call).SharedContext)) { return(MakeAbstractInstantiationError(call, ai, valInfo)); } DynamicMetaObject translated = BuiltinFunction.TranslateArguments(call, codeContext, self, args, false, Value.Name); if (translated != null) { return(translated); } GetAdapters(ai, call, codeContext, out newAdapter, out initAdapter); PythonContext state = PythonContext.GetPythonContext(call); // get the expression for calling __new__ DynamicMetaObject createExpr = newAdapter.GetExpression(state.Binder); if (createExpr.Expression.Type == typeof(void)) { return(BindingHelpers.AddDynamicTestAndDefer( call, createExpr, args, valInfo )); } Expression res; BindingRestrictions additionalRestrictions = BindingRestrictions.Empty; if (!Value.IsSystemType && (!(newAdapter is DefaultNewAdapter) || HasFinalizer(call))) { // we need to dynamically check the return value to see if it's a subtype of // the type that we are calling. If it is then we need to call __init__/__del__ // for the actual returned type. res = Expression.Dynamic( Value.GetLateBoundInitBinder(sig), typeof(object), ArrayUtils.Insert( codeContext, Expression.Convert(createExpr.Expression, typeof(object)), DynamicUtils.GetExpressions(args) ) ); additionalRestrictions = createExpr.Restrictions; } else { // just call the __init__ method, built-in types currently have // no wacky return values which don't return the derived type. // then get the statement for calling __init__ ParameterExpression allocatedInst = Ast.Variable(createExpr.GetLimitType(), "newInst"); Expression tmpRead = allocatedInst; DynamicMetaObject initCall = initAdapter.MakeInitCall( state.Binder, new RestrictedMetaObject( AstUtils.Convert(allocatedInst, Value.UnderlyingSystemType), createExpr.Restrictions ) ); List <Expression> body = new List <Expression>(); Debug.Assert(!HasFinalizer(call)); // add the call to init if we need to if (initCall.Expression != tmpRead) { // init can fail but if __new__ returns a different type // no exception is raised. DynamicMetaObject initStmt = initCall; if (body.Count == 0) { body.Add( Ast.Assign(allocatedInst, createExpr.Expression) ); } if (!Value.UnderlyingSystemType.IsAssignableFrom(createExpr.Expression.Type)) { // return type of object, we need to check the return type before calling __init__. body.Add( AstUtils.IfThen( Ast.TypeIs(allocatedInst, Value.UnderlyingSystemType), initStmt.Expression ) ); } else { // just call the __init__ method, no type check necessary (TODO: need null check?) body.Add(initStmt.Expression); } } // and build the target from everything we have if (body.Count == 0) { res = createExpr.Expression; } else { body.Add(allocatedInst); res = Ast.Block(body); } res = Ast.Block(new ParameterExpression[] { allocatedInst }, res); additionalRestrictions = initCall.Restrictions; } return(BindingHelpers.AddDynamicTestAndDefer( call, new DynamicMetaObject( res, self.Restrictions.Merge(additionalRestrictions) ), ArrayUtils.Insert(this, args), valInfo )); }
private DynamicMetaObject/*!*/ MakeConvertToBool(DynamicMetaObjectBinder/*!*/ conversion) { DynamicMetaObject self = Restrict(typeof(OldInstance)); ParameterExpression tmp = Ast.Variable(typeof(bool?), "tmp"); DynamicMetaObject fallback = FallbackConvert(conversion); Type resType = BindingHelpers.GetCompatibleType(typeof(bool), fallback.Expression.Type); return new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.NotEqual( Ast.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod("OldInstanceConvertToBoolNonThrowing"), AstUtils.Constant(PythonContext.GetPythonContext(conversion).SharedContext), self.Expression ) ), AstUtils.Constant(null) ), AstUtils.Convert(tmp, resType), AstUtils.Convert(fallback.Expression, resType) ) ), self.Restrictions ); }
private InitAdapter /*!*/ GetInitAdapter(ArgumentValues /*!*/ ai, PythonTypeSlot /*!*/ init, DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext) { PythonContext state = PythonContext.GetPythonContext(call); if (Value.IsMixedNewStyleOldStyle()) { return(new MixedInitAdapter(ai, state, codeContext)); } else if ((init == InstanceOps.Init && !HasFinalizer(call)) || (Value == TypeCache.PythonType && ai.Arguments.Length == 2)) { return(new DefaultInitAdapter(ai, state, codeContext)); } else if (init is BuiltinMethodDescriptor) { return(new BuiltinInitAdapter(ai, ((BuiltinMethodDescriptor)init).Template, state, codeContext)); } else if (init is BuiltinFunction) { return(new BuiltinInitAdapter(ai, (BuiltinFunction)init, state, codeContext)); } else { return(new SlotInitAdapter(init, ai, state, codeContext)); } }
private DynamicMetaObject/*!*/ MakeDynamicMemberAccess(DynamicMetaObjectBinder/*!*/ member, string/*!*/ name, MemberAccess access, DynamicMetaObject/*!*/[]/*!*/ args) { DynamicMetaObject self = Restrict(typeof(OldInstance)); Expression target; ParameterExpression tmp = Ast.Variable(typeof(object), "result"); switch (access) { case MemberAccess.Invoke: target = Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.Call( typeof(PythonOps).GetMethod("OldInstanceTryGetBoundCustomMember"), Ast.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name), tmp ), ((InvokeMemberBinder)member).FallbackInvoke(new DynamicMetaObject(tmp, BindingRestrictions.Empty), args, null).Expression, AstUtils.Convert( ((InvokeMemberBinder)member).FallbackInvokeMember(this, args).Expression, typeof(object) ) ) ); break; case MemberAccess.Get: target = Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.Call( typeof(PythonOps).GetMethod("OldInstanceTryGetBoundCustomMember"), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name), tmp ), tmp, AstUtils.Convert( FallbackGet(member, args), typeof(object) ) ) ); break; case MemberAccess.Set: target = Ast.Call( typeof(PythonOps).GetMethod("OldInstanceSetCustomMember"), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name), AstUtils.Convert(args[1].Expression, typeof(object)) ); break; case MemberAccess.Delete: target = Ast.Call( typeof(PythonOps).GetMethod("OldInstanceDeleteCustomMember"), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(name) ); break; default: throw new InvalidOperationException(); } return new DynamicMetaObject( target, self.Restrictions.Merge(BindingRestrictions.Combine(args)) ); }
private NewAdapter /*!*/ GetNewAdapter(ArgumentValues /*!*/ ai, PythonTypeSlot /*!*/ newInst, DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext) { PythonContext state = PythonContext.GetPythonContext(call); if (Value.IsMixedNewStyleOldStyle()) { return(new MixedNewAdapter(ai, state, codeContext)); } else if (newInst == InstanceOps.New) { return(new DefaultNewAdapter(ai, Value, state, codeContext)); } else if (newInst is ConstructorFunction) { return(new ConstructorNewAdapter(ai, Value, state, codeContext)); } else if (newInst is BuiltinFunction) { return(new BuiltinNewAdapter(ai, Value, ((BuiltinFunction)newInst), state, codeContext)); } return(new NewAdapter(ai, state, codeContext)); }
private static ConstantExpression Constant(DynamicMetaObjectBinder binder) { Type t = binder.GetType(); return(Expression.Constant(binder, t)); }
private bool HasDefaultNewAndInit(DynamicMetaObjectBinder /*!*/ action) { return(HasDefaultNew(action) && HasDefaultInit(action)); }
/// <summary> /// Helper method for generating a MetaObject which calls a /// specific method on DynamicObject that returns a result. /// /// args is either an array of arguments to be passed /// to the method as an object[] or NoArgs to signify that /// the target method takes no parameters. /// </summary> private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, DynamicMetaObject fallbackResult, Fallback fallbackInvoke) { if (!IsOverridden(methodName)) { return(fallbackResult); } // // Build a new expression like: // { // object result; // TryGetMember(payload, out result) ? fallbackInvoke(result) : fallbackResult // } // var result = Expression.Parameter(typeof(object), null); ParameterExpression callArgs = methodName != "TryBinaryOperation" ? Expression.Parameter(typeof(object[]), null) : Expression.Parameter(typeof(object), null); var callArgsValue = GetConvertedArgs(args); var resultMO = new DynamicMetaObject(result, BindingRestrictions.Empty); // Need to add a conversion if calling TryConvert if (binder.ReturnType != typeof(object)) { Debug.Assert(binder is ConvertBinder && fallbackInvoke == null); var convert = Expression.Convert(resultMO.Expression, binder.ReturnType); // will always be a cast or unbox Debug.Assert(convert.Method == null); // Prepare a good exception message in case the convert will fail string convertFailed = string.Format( "The result type '{0}' of the dynamic binding produced by the object with type '{1}' for the binder '{2}' is not compati ble with the result type '{3}' expected by the call site.", "{0}", this.Value.GetType(), binder.GetType(), binder.ReturnType ); var checkedConvert = Expression.Condition( Expression.TypeIs(resultMO.Expression, binder.ReturnType), convert, Expression.Throw( Expression.New(typeof(InvalidCastException).GetConstructor(new Type[] { typeof(string) }), Expression.Call( typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object) }), Expression.Constant(convertFailed), Expression.Condition( Expression.Equal(resultMO.Expression, Expression.Constant(null)), Expression.Constant("null"), Expression.Call( resultMO.Expression, typeof(object).GetMethod("GetType") ), typeof(object) ) ) ), binder.ReturnType ), binder.ReturnType ); resultMO = new DynamicMetaObject(checkedConvert, resultMO.Restrictions); } if (fallbackInvoke != null) { resultMO = fallbackInvoke(resultMO); } var callDynamic = new DynamicMetaObject( Expression.Block( new[] { result, callArgs }, methodName != "TryBinaryOperation" ? Expression.Assign(callArgs, Expression.NewArrayInit(typeof(object), callArgsValue)) : Expression.Assign(callArgs, callArgsValue[0]), Expression.Condition( Expression.Call( GetLimitedSelf(), ValueType.GetMethod(methodName), BuildCallArgs( binder, args, callArgs, result ) ), Expression.Block( methodName != "TryBinaryOperation" ? ReferenceArgAssign(callArgs, args) : Expression.Empty(), resultMO.Expression ), fallbackResult.Expression, binder.ReturnType ) ), GetRestrictions().Merge(resultMO.Restrictions).Merge(fallbackResult.Restrictions) ); return(callDynamic); }
private DynamicMetaObject /*!*/ MakeGetMember(DynamicMetaObjectBinder /*!*/ member, DynamicMetaObject codeContext) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass GetMember"); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass GetMember"); DynamicMetaObject self = Restrict(typeof(OldClass)); Expression target; string memberName = GetGetMemberName(member); switch (memberName) { case "__dict__": target = Ast.Block( Ast.Call( typeof(PythonOps).GetMethod("OldClassDictionaryIsPublic"), self.Expression ), Ast.Call( typeof(PythonOps).GetMethod("OldClassGetDictionary"), self.Expression ) ); break; case "__bases__": target = Ast.Call( typeof(PythonOps).GetMethod("OldClassGetBaseClasses"), self.Expression ); break; case "__name__": target = Ast.Call( typeof(PythonOps).GetMethod("OldClassGetName"), self.Expression ); break; default: ParameterExpression tmp = Ast.Variable(typeof(object), "lookupVal"); return(new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Expression.Not( Expression.TypeIs( Expression.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod("OldClassTryLookupValue"), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(memberName) ) ), typeof(OperationFailed) ) ), tmp, AstUtils.Convert( GetMemberFallback(this, member, codeContext).Expression, typeof(object) ) ) ), self.Restrictions )); } return(new DynamicMetaObject( target, self.Restrictions )); }
private DynamicMetaObject /*!*/ MakeConvertRuleForCall(DynamicMetaObjectBinder /*!*/ convertToAction, Type toType, DynamicMetaObject /*!*/ self, string name, string returner) { return(MakeConvertRuleForCall(convertToAction, toType, self, name, returner, () => FallbackConvert(convertToAction), (x) => x)); }
private DynamicMetaObject /*!*/ InvokeWorker(DynamicMetaObjectBinder /*!*/ invoke, Expression /*!*/ codeContext, DynamicMetaObject /*!*/[] args) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass Invoke"); DynamicMetaObject self = Restrict(typeof(OldInstance)); Expression[] exprArgs = new Expression[args.Length + 1]; for (int i = 0; i < args.Length; i++) { exprArgs[i + 1] = args[i].Expression; } ParameterExpression tmp = Ast.Variable(typeof(object), "callFunc"); exprArgs[0] = tmp; return(new DynamicMetaObject( // we could get better throughput w/ a more specific rule against our current custom old class but // this favors less code generation. Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Expression.Not( Expression.TypeIs( Expression.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldInstanceTryGetBoundCustomMember)), codeContext, self.Expression, AstUtils.Constant("__call__") ) ), typeof(OperationFailed) ) ), Ast.Block( Utils.Try( Ast.Call(typeof(PythonOps).GetMethod(nameof(PythonOps.FunctionPushFrameCodeContext)), codeContext), Ast.Assign( tmp, DynamicExpression.Dynamic( PythonContext.GetPythonContext(invoke).Invoke( BindingHelpers.GetCallSignature(invoke) ), typeof(object), ArrayUtils.Insert(codeContext, exprArgs) ) ) ).Finally( Ast.Call(typeof(PythonOps).GetMethod(nameof(PythonOps.FunctionPopFrame))) ), tmp ), Utils.Convert( BindingHelpers.InvokeFallback(invoke, codeContext, this, args).Expression, typeof(object) ) ) ), self.Restrictions.Merge(BindingRestrictions.Combine(args)) )); }