Esempio n. 1
0
        /// <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);
        }