/// <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); }