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(); }
private DynamicMetaObject/*!*/ InvokeWorker(DynamicMetaObjectBinder/*!*/ call, Expression/*!*/ codeContext, DynamicMetaObject/*!*/[]/*!*/ args) { 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); } }
internal DynamicMetaObject/*!*/ CreateMetaObject(DynamicMetaObjectBinder/*!*/ action, DynamicMetaObject/*!*/[]/*!*/ siteArgs) { Debug.Assert(ControlFlowBuilder == null, "Control flow required but not built"); var expr = _error ? Ast.Throw(_result) : _result; BindingRestrictions restrictions; if (_condition != null) { var deferral = action.Defer(siteArgs); expr = Ast.Condition(_condition, AstUtils.Convert(expr, typeof(object)), deferral.Expression); restrictions = deferral.Restrictions; } else { restrictions = BindingRestrictions.Empty; } if (_temps != null) { expr = Ast.Block(_temps, expr); } if (_restriction != null) { restrictions = restrictions.Merge(BindingRestrictions.GetExpressionRestriction(_restriction)); } return new DynamicMetaObject(expr, restrictions); }
internal static DynamicMetaObject FallbackWorker(DynamicMetaObject/*!*/ self, Expression/*!*/ codeContext, string name, GetMemberOptions options, DynamicMetaObjectBinder action) { if (self.NeedsDeferral()) { return action.Defer(self); } 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 = BinderState.GetBinderState(action).Binder.GetMember( name, self, codeContext, isNoThrow ); Expression failure = GetFailureExpression(limitType, name, isNoThrow, action); return BindingHelpers.FilterShowCls(codeContext, action, baseRes, failure); } } if (self.GetLimitType() == typeof(OldInstance)) { if ((options & GetMemberOptions.IsNoThrow) != 0) { return new DynamicMetaObject( Ast.Field( null, typeof(OperationFailed).GetField("Value") ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance))) ); } else { return new DynamicMetaObject( Ast.Throw( Ast.Call( typeof(PythonOps).GetMethod("AttributeError"), Ast.Constant("{0} instance has no attribute '{1}'"), Ast.NewArrayInit( typeof(object), Ast.Constant(((OldInstance)self.Value)._class._name), Ast.Constant(name) ) ) ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance))) ); } } var res = BinderState.GetBinderState(action).Binder.GetMember(name, self, codeContext, isNoThrow); // 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 == typeof(bool) || res.Expression.Type == typeof(int)) { res = new DynamicMetaObject( AstUtils.Convert(res.Expression, typeof(object)), res.Restrictions ); } return res; }
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; }
/// <summary> /// Adds a dynamic test which checks if the version has changed. The test is only necessary for /// performance as the methods will do the correct thing if called with an incorrect version. /// </summary> private DynamicMetaObject AddDynamicTestAndDefer( DynamicMetaObjectBinder binder, DynamicMetaObject[] args, ExpandoClass klass, ExpandoClass originalClass, DynamicMetaObject succeeds) { Expression ifTestSucceeds = succeeds.Expression; if (originalClass != null) { // we are accessing a member which has not yet been defined on this class. // We force a class promotion after the type check. If the class changes the // promotion will fail and the set/delete will do a full lookup using the new // class to discover the name. Debug.Assert(originalClass != klass); ifTestSucceeds = Helpers.Convert( Expression.Block( Expression.Call( null, typeof(RuntimeOps).GetMethod("ExpandoPromoteClass"), GetLimitedSelf(), Expression.Constant(originalClass), Expression.Constant(klass) ), succeeds.Expression ), typeof(object) ); } return new DynamicMetaObject( Expression.Condition( Expression.Call( null, typeof(RuntimeOps).GetMethod("ExpandoCheckVersion"), GetLimitedSelf(), Expression.Constant(originalClass ?? klass) ), Helpers.Convert(ifTestSucceeds, typeof(object)), Helpers.Convert(binder.Defer(args).Expression, typeof(object)) ), GetRestrictions().Merge(succeeds.Restrictions) ); }