PyTuple_GetSlice() private méthode

private PyTuple_GetSlice ( IntPtr pointer, int start, int end ) : IntPtr
pointer IntPtr
start int
end int
Résultat IntPtr
        static IntPtr HandleParamsArray(IntPtr args, int arrayStart, int pyArgCount, out bool isNewReference)
        {
            isNewReference = false;
            IntPtr op;

            // for a params method, we may have a sequence or single/multiple items
            // here we look to see if the item at the paramIndex is there or not
            // and then if it is a sequence itself.
            if ((pyArgCount - arrayStart) == 1)
            {
                // we only have one argument left, so we need to check it
                // to see if it is a sequence or a single item
                IntPtr item = Runtime.PyTuple_GetItem(args, arrayStart);
                if (!Runtime.PyString_Check(item) && Runtime.PySequence_Check(item))
                {
                    // it's a sequence (and not a string), so we use it as the op
                    op = item;
                }
                else
                {
                    isNewReference = true;
                    op             = Runtime.PyTuple_GetSlice(args, arrayStart, pyArgCount);
                }
            }
            else
            {
                isNewReference = true;
                op             = Runtime.PyTuple_GetSlice(args, arrayStart, pyArgCount);
            }
            return(op);
        }
Exemple #2
0
        static IntPtr HandleParamsArray(IntPtr args, int arrayStart, int pyArgCount, out bool isNewReference)
        {
            isNewReference = false;
            IntPtr op;

            // for a params method, we may have a sequence or single/multiple items
            // here we look to see if the item at the paramIndex is there or not
            // and then if it is a sequence itself.
            if ((pyArgCount - arrayStart) == 1)
            {
                // Ee only have one argument left, so we need to check to see if it is a sequence or a single item
                // We also need to check if this object is possibly a wrapped C# Enumerable Object
                IntPtr item = Runtime.PyTuple_GetItem(args, arrayStart);
                if (!Runtime.PyString_Check(item) && (Runtime.PySequence_Check(item) || (ManagedType.GetManagedObject(item) as CLRObject)?.inst is IEnumerable))
                {
                    // it's a sequence (and not a string), so we use it as the op
                    op = item;
                }
                else
                {
                    // Its a single value that needs to be converted into the params array
                    isNewReference = true;
                    op             = Runtime.PyTuple_GetSlice(args, arrayStart, pyArgCount);
                }
            }
            else
            {
                // Its a set of individual values, so we grab them as a tuple to be converted into the params array
                isNewReference = true;
                op             = Runtime.PyTuple_GetSlice(args, arrayStart, pyArgCount);
            }
            return(op);
        }
Exemple #3
0
        public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)
        {
            MethodBinding self = (MethodBinding)GetManagedObject(ob);

            // This supports calling a method 'unbound', passing the instance
            // as the first argument. Note that this is not supported if any
            // of the overloads are static since we can't know if the intent
            // was to call the static method or the unbound instance method.

            if ((self.target == IntPtr.Zero) && (!self.m.IsStatic()))
            {
                if (Runtime.PyTuple_Size(args) < 1)
                {
                    Exceptions.SetError(Exceptions.TypeError,
                                        "not enough arguments"
                                        );
                    return(IntPtr.Zero);
                }
                int    len   = Runtime.PyTuple_Size(args);
                IntPtr uargs = Runtime.PyTuple_GetSlice(args, 1, len);
                IntPtr inst  = Runtime.PyTuple_GetItem(args, 0);
                Runtime.Incref(inst);
                IntPtr r = self.m.Invoke(inst, uargs, kw, self.info);
                Runtime.Decref(inst);
                Runtime.Decref(uargs);
                return(r);
            }

            return(self.m.Invoke(self.target, args, kw, self.info));
        }
Exemple #4
0
        /// <summary>
        /// Attempts to convert Python argument tuple into an array of managed objects,
        /// that can be passed to a method.
        /// </summary>
        /// <param name="pi">Information about expected parameters</param>
        /// <param name="paramsArray"><c>true</c>, if the last parameter is a params array.</param>
        /// <param name="args">A pointer to the Python argument tuple</param>
        /// <param name="pyArgCount">Number of arguments, passed by Python</param>
        /// <param name="defaultArgList">A list of default values for omitted parameters</param>
        /// <param name="needsResolution"><c>true</c>, if overloading resolution is required</param>
        /// <param name="outs">Returns number of output parameters</param>
        /// <returns>An array of .NET arguments, that can be passed to a method.</returns>
        static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
                                            IntPtr args, int pyArgCount,
                                            ArrayList defaultArgList,
                                            bool needsResolution,
                                            out int outs)
        {
            outs = 0;
            var margs      = new object[pi.Length];
            int arrayStart = paramsArray ? pi.Length - 1 : -1;

            for (int paramIndex = 0; paramIndex < pi.Length; paramIndex++)
            {
                if (paramIndex >= pyArgCount)
                {
                    if (defaultArgList != null)
                    {
                        margs[paramIndex] = defaultArgList[paramIndex - pyArgCount];
                    }

                    continue;
                }

                var    parameter = pi[paramIndex];
                IntPtr op        = (arrayStart == paramIndex)
                                   // map remaining Python arguments to a tuple since
                                   // the managed function accepts it - hopefully :]
                    ? Runtime.PyTuple_GetSlice(args, arrayStart, pyArgCount)
                    : Runtime.PyTuple_GetItem(args, paramIndex);

                bool isOut;
                if (!TryConvertArgument(op, parameter.ParameterType, needsResolution, out margs[paramIndex], out isOut))
                {
                    return(null);
                }

                if (arrayStart == paramIndex)
                {
                    Console.WriteLine("--CHECK THIS!!!!");
                    // TODO: is this a bug? Should this happen even if the conversion fails?
                    // GetSlice() creates a new reference but GetItem()
                    // returns only a borrow reference.
                    Runtime.XDecref(op);
                }

                if (parameter.IsOut || isOut)
                {
                    outs++;
                }
            }

            return(margs);
        }
Exemple #5
0
        //====================================================================
        // MethodBinding  __call__ implementation.
        //====================================================================

        public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)
        {
            MethodBinding self = (MethodBinding)GetManagedObject(ob);

            // This works around a situation where the wrong generic method is picked,
            // for example this method in the tests: string Overloaded<T>(int arg1, int arg2, string arg3)
            if (self.info != null)
            {
                if (self.info.IsGenericMethod)
                {
                    int    len   = Runtime.PyTuple_Size(args);
                    Type[] sigTp = Runtime.PythonArgsToTypeArray(args, true);
                    if (sigTp != null)
                    {
                        Type[]     genericTp   = self.info.GetGenericArguments();
                        MethodInfo betterMatch = MethodBinder.MatchSignatureAndParameters(self.m.info, genericTp, sigTp);
                        if (betterMatch != null)
                        {
                            self.info = betterMatch;
                        }
                    }
                }
            }

            // This supports calling a method 'unbound', passing the instance
            // as the first argument. Note that this is not supported if any
            // of the overloads are static since we can't know if the intent
            // was to call the static method or the unbound instance method.

            if ((self.target == IntPtr.Zero) && (!self.m.IsStatic()))
            {
                int len = Runtime.PyTuple_Size(args);
                if (len < 1)
                {
                    Exceptions.SetError(Exceptions.TypeError, "not enough arguments");
                    return(IntPtr.Zero);
                }
                IntPtr uargs = Runtime.PyTuple_GetSlice(args, 1, len);
                IntPtr inst  = Runtime.PyTuple_GetItem(args, 0);
                Runtime.Incref(inst);
                IntPtr r = self.m.Invoke(inst, uargs, kw, self.info);
                Runtime.Decref(inst);
                Runtime.Decref(uargs);
                return(r);
            }

            return(self.m.Invoke(self.target, args, kw, self.info));
        }
Exemple #6
0
        internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
                              MethodBase info, MethodInfo[] methodinfo)
        {
            // loop to find match, return invoker w/ or /wo error
            MethodBase[] _methods = null;
            int          pynargs  = Runtime.PyTuple_Size(args);
            object       arg;
            bool         isGeneric = false;

            if (info != null)
            {
                _methods = (MethodBase[])Array.CreateInstance(
                    typeof(MethodBase), 1
                    );
                _methods.SetValue(info, 0);
            }
            else
            {
                _methods = GetMethods();
            }

            for (int i = 0; i < _methods.Length; i++)
            {
                MethodBase mi = _methods[i];
                if (mi.IsGenericMethod)
                {
                    isGeneric = true;
                }
                ParameterInfo[] pi         = mi.GetParameters();
                int             clrnargs   = pi.Length;
                bool            match      = false;
                int             arrayStart = -1;
                int             outs       = 0;

                if (pynargs == clrnargs)
                {
                    match = true;
                }
                else if ((pynargs > clrnargs) && (clrnargs > 0) &&
                         (pi[clrnargs - 1].ParameterType.IsArray))
                {
                    // The last argument of the mananged functions seems to
                    // accept multiple arguments as a array. Hopefully it's a
                    // spam(params object[] egg) style method
                    match      = true;
                    arrayStart = clrnargs - 1;
                }

                if (match)
                {
                    Object[] margs = new Object[clrnargs];

                    for (int n = 0; n < clrnargs; n++)
                    {
                        IntPtr op;
                        if (arrayStart == n)
                        {
                            // map remaining Python arguments to a tuple since
                            // the managed function accepts it - hopefully :]
                            op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
                        }
                        else
                        {
                            op = Runtime.PyTuple_GetItem(args, n);
                        }
                        Type type = pi[n].ParameterType;
                        if (pi[n].IsOut || type.IsByRef)
                        {
                            outs++;
                        }

                        if (!Converter.ToManaged(op, type, out arg, false))
                        {
                            Exceptions.Clear();
                            margs = null;
                            break;
                        }
                        if (arrayStart == n)
                        {
                            // GetSlice() creates a new reference but GetItem()
                            // returns only a borrow reference.
                            Runtime.Decref(op);
                        }
                        margs[n] = arg;
                    }

                    if (margs == null)
                    {
                        continue;
                    }

                    Object target = null;
                    if ((!mi.IsStatic) && (inst != IntPtr.Zero))
                    {
                        //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
                        // InvalidCastException: Unable to cast object of type
                        // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
                        CLRObject co = ManagedType.GetManagedObject(inst) as CLRObject;

                        // Sanity check: this ensures a graceful exit if someone does
                        // something intentionally wrong like call a non-static method
                        // on the class rather than on an instance of the class.
                        // XXX maybe better to do this before all the other rigmarole.
                        if (co == null)
                        {
                            return(null);
                        }
                        target = co.inst;
                    }

                    return(new Binding(mi, target, margs, outs));
                }
            }
            // We weren't able to find a matching method but at least one
            // is a generic method and info is null. That happens when a generic
            // method was not called using the [] syntax. Let's introspect the
            // type of the arguments and use it to construct the correct method.
            if (isGeneric && (info == null) && (methodinfo != null))
            {
                Type[]     types = Runtime.PythonArgsToTypeArray(args, true);
                MethodInfo mi    = MethodBinder.MatchParameters(methodinfo, types);
                return(Bind(inst, args, kw, mi, null));
            }
            return(null);
        }
Exemple #7
0
        /// <summary>
        /// MethodBinding  __call__ implementation.
        /// </summary>
        public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)
        {
            var self = (MethodBinding)GetManagedObject(ob);

            // This works around a situation where the wrong generic method is picked,
            // for example this method in the tests: string Overloaded<T>(int arg1, int arg2, string arg3)
            if (self.info != null)
            {
                if (self.info.IsGenericMethod)
                {
                    var    len   = Runtime.PyTuple_Size(args); //FIXME: Never used
                    Type[] sigTp = Runtime.PythonArgsToTypeArray(args, true);
                    if (sigTp != null)
                    {
                        Type[]     genericTp   = self.info.GetGenericArguments();
                        MethodInfo betterMatch = MethodBinder.MatchSignatureAndParameters(self.m.info, genericTp, sigTp);
                        if (betterMatch != null)
                        {
                            self.info = betterMatch;
                        }
                    }
                }
            }

            // This supports calling a method 'unbound', passing the instance
            // as the first argument. Note that this is not supported if any
            // of the overloads are static since we can't know if the intent
            // was to call the static method or the unbound instance method.
            var disposeList = new List <IntPtr>();

            try
            {
                IntPtr target = self.target;

                if (target == IntPtr.Zero && !self.m.IsStatic())
                {
                    var len = Runtime.PyTuple_Size(args);
                    if (len < 1)
                    {
                        Exceptions.SetError(Exceptions.TypeError, "not enough arguments");
                        return(IntPtr.Zero);
                    }
                    target = Runtime.PyTuple_GetItem(args, 0);
                    Runtime.XIncref(target);
                    disposeList.Add(target);

                    args = Runtime.PyTuple_GetSlice(args, 1, len);
                    disposeList.Add(args);
                }

                // if the class is a IPythonDerivedClass and target is not the same as self.targetType
                // (eg if calling the base class method) then call the original base class method instead
                // of the target method.
                IntPtr superType = IntPtr.Zero;
                if (Runtime.PyObject_TYPE(target) != self.targetType)
                {
                    var inst = GetManagedObject(target) as CLRObject;
                    if (inst?.inst is IPythonDerivedType)
                    {
                        var baseType = GetManagedObject(self.targetType) as ClassBase;
                        if (baseType != null)
                        {
                            string baseMethodName = "_" + baseType.type.Name + "__" + self.m.name;
                            IntPtr baseMethod     = Runtime.PyObject_GetAttrString(target, baseMethodName);
                            if (baseMethod != IntPtr.Zero)
                            {
                                var baseSelf = GetManagedObject(baseMethod) as MethodBinding;
                                if (baseSelf != null)
                                {
                                    self = baseSelf;
                                }
                                Runtime.XDecref(baseMethod);
                            }
                            else
                            {
                                Runtime.PyErr_Clear();
                            }
                        }
                    }
                }

                return(self.m.Invoke(target, args, kw, self.info));
            }
            finally
            {
                foreach (IntPtr ptr in disposeList)
                {
                    Runtime.XDecref(ptr);
                }
            }
        }
        internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo)
        {
            // loop to find match, return invoker w/ or /wo error
            MethodBase[] _methods = null;
            int          pynargs  = Runtime.PyTuple_Size(args);
            object       arg;
            var          isGeneric      = false;
            ArrayList    defaultArgList = null;

            if (info != null)
            {
                _methods = new MethodBase[1];
                _methods.SetValue(info, 0);
            }
            else
            {
                _methods = GetMethods();
            }
            Type clrtype;

            // TODO: Clean up
            foreach (MethodBase mi in _methods)
            {
                if (mi.IsGenericMethod)
                {
                    isGeneric = true;
                }
                ParameterInfo[] pi         = mi.GetParameters();
                int             clrnargs   = pi.Length;
                var             match      = false;
                int             arrayStart = -1;
                var             outs       = 0;

                if (pynargs == clrnargs)
                {
                    match = true;
                }
                else if (pynargs < clrnargs)
                {
                    match          = true;
                    defaultArgList = new ArrayList();
                    for (int v = pynargs; v < clrnargs; v++)
                    {
                        if (pi[v].DefaultValue == DBNull.Value)
                        {
                            match = false;
                        }
                        else
                        {
                            defaultArgList.Add(pi[v].DefaultValue);
                        }
                    }
                }
                else if (pynargs > clrnargs && clrnargs > 0 &&
                         Attribute.IsDefined(pi[clrnargs - 1], typeof(ParamArrayAttribute)))
                {
                    // This is a `foo(params object[] bar)` style method
                    match      = true;
                    arrayStart = clrnargs - 1;
                }

                if (match)
                {
                    var margs = new object[clrnargs];

                    for (var n = 0; n < clrnargs; n++)
                    {
                        IntPtr op;
                        if (n < pynargs)
                        {
                            if (arrayStart == n)
                            {
                                // map remaining Python arguments to a tuple since
                                // the managed function accepts it - hopefully :]
                                op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
                            }
                            else
                            {
                                op = Runtime.PyTuple_GetItem(args, n);
                            }

                            // this logic below handles cases when multiple overloading methods
                            // are ambiguous, hence comparison between Python and CLR types
                            // is necessary
                            clrtype = null;
                            IntPtr pyoptype;
                            if (_methods.Length > 1)
                            {
                                pyoptype = IntPtr.Zero;
                                pyoptype = Runtime.PyObject_Type(op);
                                Exceptions.Clear();
                                if (pyoptype != IntPtr.Zero)
                                {
                                    clrtype = Converter.GetTypeByAlias(pyoptype);
                                }
                                Runtime.XDecref(pyoptype);
                            }


                            if (clrtype != null)
                            {
                                var typematch = false;
                                if ((pi[n].ParameterType != typeof(object)) && (pi[n].ParameterType != clrtype))
                                {
                                    IntPtr pytype = Converter.GetPythonTypeByAlias(pi[n].ParameterType);
                                    pyoptype = Runtime.PyObject_Type(op);
                                    Exceptions.Clear();
                                    if (pyoptype != IntPtr.Zero)
                                    {
                                        if (pytype != pyoptype)
                                        {
                                            typematch = false;
                                        }
                                        else
                                        {
                                            typematch = true;
                                            clrtype   = pi[n].ParameterType;
                                        }
                                    }
                                    if (!typematch)
                                    {
                                        // this takes care of nullables
                                        var underlyingType = Nullable.GetUnderlyingType(pi[n].ParameterType);
                                        if (underlyingType == null)
                                        {
                                            underlyingType = pi[n].ParameterType;
                                        }
                                        // this takes care of enum values
                                        TypeCode argtypecode   = Type.GetTypeCode(underlyingType);
                                        TypeCode paramtypecode = Type.GetTypeCode(clrtype);
                                        if (argtypecode == paramtypecode)
                                        {
                                            typematch = true;
                                            clrtype   = pi[n].ParameterType;
                                        }
                                        // this takes care of implicit conversions
                                        var opImplicit = pi[n].ParameterType.GetMethod("op_Implicit", new[] { clrtype });
                                        if (opImplicit != null)
                                        {
                                            typematch = opImplicit.ReturnType == pi[n].ParameterType;
                                            clrtype   = pi[n].ParameterType;
                                        }
                                    }
                                    Runtime.XDecref(pyoptype);
                                    if (!typematch)
                                    {
                                        margs = null;
                                        break;
                                    }
                                }
                                else
                                {
                                    typematch = true;
                                    clrtype   = pi[n].ParameterType;
                                }
                            }
                            else
                            {
                                clrtype = pi[n].ParameterType;
                            }

                            if (pi[n].IsOut || clrtype.IsByRef)
                            {
                                outs++;
                            }

                            if (!Converter.ToManaged(op, clrtype, out arg, false))
                            {
                                Exceptions.Clear();
                                margs = null;
                                break;
                            }
                            if (arrayStart == n)
                            {
                                // GetSlice() creates a new reference but GetItem()
                                // returns only a borrow reference.
                                Runtime.XDecref(op);
                            }
                            margs[n] = arg;
                        }
                        else
                        {
                            if (defaultArgList != null)
                            {
                                margs[n] = defaultArgList[n - pynargs];
                            }
                        }
                    }

                    if (margs == null)
                    {
                        continue;
                    }

                    object target = null;
                    if (!mi.IsStatic && inst != IntPtr.Zero)
                    {
                        //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
                        // InvalidCastException: Unable to cast object of type
                        // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
                        var co = ManagedType.GetManagedObject(inst) as CLRObject;

                        // Sanity check: this ensures a graceful exit if someone does
                        // something intentionally wrong like call a non-static method
                        // on the class rather than on an instance of the class.
                        // XXX maybe better to do this before all the other rigmarole.
                        if (co == null)
                        {
                            return(null);
                        }
                        target = co.inst;
                    }

                    return(new Binding(mi, target, margs, outs));
                }
            }
            // We weren't able to find a matching method but at least one
            // is a generic method and info is null. That happens when a generic
            // method was not called using the [] syntax. Let's introspect the
            // type of the arguments and use it to construct the correct method.
            if (isGeneric && info == null && methodinfo != null)
            {
                Type[]     types = Runtime.PythonArgsToTypeArray(args, true);
                MethodInfo mi    = MatchParameters(methodinfo, types);
                return(Bind(inst, args, kw, mi, null));
            }
            return(null);
        }
Exemple #9
0
        internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo)
        {
            // loop to find match, return invoker w/ or /wo error
            int       pynargs = Runtime.PyTuple_Size(args);
            object    arg;
            var       isGeneric = false;
            ArrayList defaultArgList;
            Type      clrtype;
            Binding   bindingUsingImplicitConversion = null;

            var methods = info == null?GetMethods()
                              : new List <MethodInformation>(1)
            {
                new MethodInformation(info, info.GetParameters())
            };

            // TODO: Clean up
            foreach (var methodInformation in methods)
            {
                var mi = methodInformation.MethodBase;
                var pi = methodInformation.ParameterInfo;

                if (mi.IsGenericMethod)
                {
                    isGeneric = true;
                }
                int clrnargs = pi.Length;
                int arrayStart;

                if (CheckMethodArgumentsMatch(clrnargs,
                                              pynargs,
                                              pi,
                                              out arrayStart,
                                              out defaultArgList))
                {
                    var outs  = 0;
                    var margs = new object[clrnargs];
                    var usedImplicitConversion = false;

                    for (var n = 0; n < clrnargs; n++)
                    {
                        IntPtr op;
                        if (n < pynargs)
                        {
                            if (arrayStart == n)
                            {
                                // map remaining Python arguments to a tuple since
                                // the managed function accepts it - hopefully :]
                                op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
                            }
                            else
                            {
                                op = Runtime.PyTuple_GetItem(args, n);
                            }

                            // this logic below handles cases when multiple overloading methods
                            // are ambiguous, hence comparison between Python and CLR types
                            // is necessary
                            clrtype = null;
                            IntPtr pyoptype;
                            if (methods.Count > 1)
                            {
                                pyoptype = IntPtr.Zero;
                                pyoptype = Runtime.PyObject_Type(op);
                                Exceptions.Clear();
                                if (pyoptype != IntPtr.Zero)
                                {
                                    clrtype = Converter.GetTypeByAlias(pyoptype);
                                }
                                Runtime.XDecref(pyoptype);
                            }


                            if (clrtype != null)
                            {
                                var typematch = false;
                                if ((pi[n].ParameterType != typeof(object)) && (pi[n].ParameterType != clrtype))
                                {
                                    IntPtr pytype = Converter.GetPythonTypeByAlias(pi[n].ParameterType);
                                    pyoptype = Runtime.PyObject_Type(op);
                                    Exceptions.Clear();
                                    if (pyoptype != IntPtr.Zero)
                                    {
                                        if (pytype != pyoptype)
                                        {
                                            typematch = false;
                                        }
                                        else
                                        {
                                            typematch = true;
                                            clrtype   = pi[n].ParameterType;
                                        }
                                    }
                                    if (!typematch)
                                    {
                                        // this takes care of nullables
                                        var underlyingType = Nullable.GetUnderlyingType(pi[n].ParameterType);
                                        if (underlyingType == null)
                                        {
                                            underlyingType = pi[n].ParameterType;
                                        }
                                        // this takes care of enum values
                                        TypeCode argtypecode   = Type.GetTypeCode(underlyingType);
                                        TypeCode paramtypecode = Type.GetTypeCode(clrtype);
                                        if (argtypecode == paramtypecode)
                                        {
                                            typematch = true;
                                            clrtype   = pi[n].ParameterType;
                                        }
                                        // accepts non-decimal numbers in decimal parameters
                                        if (underlyingType == typeof(decimal))
                                        {
                                            clrtype   = pi[n].ParameterType;
                                            typematch = Converter.ToManaged(op, clrtype, out arg, false);
                                        }
                                        // this takes care of implicit conversions
                                        var opImplicit = pi[n].ParameterType.GetMethod("op_Implicit", new[] { clrtype });
                                        if (opImplicit != null)
                                        {
                                            usedImplicitConversion = typematch = opImplicit.ReturnType == pi[n].ParameterType;
                                            clrtype = pi[n].ParameterType;
                                        }
                                    }
                                    Runtime.XDecref(pyoptype);
                                    if (!typematch)
                                    {
                                        margs = null;
                                        break;
                                    }
                                }
                                else
                                {
                                    typematch = true;
                                    clrtype   = pi[n].ParameterType;
                                }
                            }
                            else
                            {
                                clrtype = pi[n].ParameterType;
                            }

                            if (pi[n].IsOut || clrtype.IsByRef)
                            {
                                outs++;
                            }

                            if (!Converter.ToManaged(op, clrtype, out arg, false))
                            {
                                Exceptions.Clear();
                                margs = null;
                                break;
                            }
                            if (arrayStart == n)
                            {
                                // GetSlice() creates a new reference but GetItem()
                                // returns only a borrow reference.
                                Runtime.XDecref(op);
                            }
                            margs[n] = arg;
                        }
                        else
                        {
                            if (defaultArgList != null)
                            {
                                margs[n] = defaultArgList[n - pynargs];
                            }
                        }
                    }

                    if (margs == null)
                    {
                        continue;
                    }

                    object target = null;
                    if (!mi.IsStatic && inst != IntPtr.Zero)
                    {
                        //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
                        // InvalidCastException: Unable to cast object of type
                        // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
                        var co = ManagedType.GetManagedObject(inst) as CLRObject;

                        // Sanity check: this ensures a graceful exit if someone does
                        // something intentionally wrong like call a non-static method
                        // on the class rather than on an instance of the class.
                        // XXX maybe better to do this before all the other rigmarole.
                        if (co == null)
                        {
                            return(null);
                        }
                        target = co.inst;
                    }

                    var binding = new Binding(mi, target, margs, outs);
                    if (usedImplicitConversion)
                    {
                        // lets just keep the first binding using implicit conversion
                        // this is to respect method order/precedence
                        if (bindingUsingImplicitConversion == null)
                        {
                            // in this case we will not return the binding yet in case there is a match
                            // which does not use implicit conversions, which will return directly
                            bindingUsingImplicitConversion = binding;
                        }
                    }
                    else
                    {
                        return(binding);
                    }
                }
            }

            // if we generated a binding using implicit conversion return it
            if (bindingUsingImplicitConversion != null)
            {
                return(bindingUsingImplicitConversion);
            }

            // We weren't able to find a matching method but at least one
            // is a generic method and info is null. That happens when a generic
            // method was not called using the [] syntax. Let's introspect the
            // type of the arguments and use it to construct the correct method.
            if (isGeneric && info == null && methodinfo != null)
            {
                Type[]     types = Runtime.PythonArgsToTypeArray(args, true);
                MethodInfo mi    = MatchParameters(methodinfo, types);
                return(Bind(inst, args, kw, mi, null));
            }
            return(null);
        }
Exemple #10
0
        internal Binding Bind(IntPtr inst, IntPtr pythonParametersPtr, IntPtr kw, MethodBase info, MethodInfo[] methodInfoArray)
        {
            // loop to find match, return invoker w/ or /wo error
            MethodBase[] _methods = null;
            // NOTE: return the size of the args pointer (the number of parameter from the python call)
            int pythonParameterCount = Runtime.PyTuple_Size(pythonParametersPtr);
            //WHY: Why is that so widely scoped ?
            object    pythonManagedParameterPtr;
            var       isGeneric            = false;
            ArrayList defaultParameterList = null;

            if (info != null)
            {
                // NOTE: If a MethodBase object has been provided, create an array with only it.
                // WHY a method base is provided some times and not other ? (ex: when call a genric with a type in [])
                _methods = new MethodBase[1];
                _methods.SetValue(info, 0);
            }
            else
            {
                // NOTE: Create an array of MethodBase from teh called method/constructor
                // WHY not use the methodinfo provided?
                _methods = GetMethods();
            }
            //WHY is it so widely scoped
            Type clrConvertedParameterType;

            // TODO: Clean up
            foreach (MethodBase methodInfo in _methods)
            {
                //WHY not just do isGeneric = mi.IsGenericMethod or use it directly ?
                if (methodInfo.IsGenericMethod)
                {
                    isGeneric = true;
                }
                //NOTE: Get the parameter from the current MethodBase
                //NOTE: MethodInfo Ok
                ParameterInfo[] clrParameterInfoArray = methodInfo.GetParameters();
                //NOTE: Get the number of clr parameters
                int clrParameterCount = clrParameterInfoArray.Length;

                var paramCountMatch = false;
                //REFACTOR: Use var like the other local variables
                var clrHasParamArray    = false;
                var clrParamsArrayStart = -1;

                var byRefCount = 0;

                if (pythonParameterCount == clrParameterCount)
                {
                    paramCountMatch = true;
                }
                else if (pythonParameterCount < clrParameterCount)
                {
                    paramCountMatch      = true;
                    defaultParameterList = new ArrayList();
                    for (int v = pythonParameterCount; v < clrParameterCount; v++)
                    {
                        if (clrParameterInfoArray[v].DefaultValue == DBNull.Value)
                        {
                            paramCountMatch = false;
                        }
                        else
                        {
                            defaultParameterList.Add(clrParameterInfoArray[v].DefaultValue);
                        }
                    }
                }
                else if (pythonParameterCount > clrParameterCount && clrParameterCount > 0 &&
                         Attribute.IsDefined(clrParameterInfoArray[clrParameterCount - 1], typeof(ParamArrayAttribute)))
                {
                    // This is a `foo({...}, params object[] bar)` style method
                    paramCountMatch     = true;
                    clrHasParamArray    = true;
                    clrParamsArrayStart = clrParameterCount - 1;
                }

                if (paramCountMatch)
                {
                    var methodParametersPtrArray = new object[clrParameterCount];

                    for (var n = 0; n < clrParameterCount; n++)
                    {
                        IntPtr pythonParameterPtr;
                        if (n < pythonParameterCount)
                        {
                            if (clrParamsArrayStart == n)
                            {
                                // map remaining Python arguments to a tuple since
                                // the managed function accepts it - hopefully :]
                                //WHY: Hmmm it returns a lot of python paramter as one. isn't there a problem later ?
                                pythonParameterPtr = Runtime.PyTuple_GetSlice(pythonParametersPtr, clrParamsArrayStart, pythonParameterCount);
                            }
                            else
                            {
                                pythonParameterPtr = Runtime.PyTuple_GetItem(pythonParametersPtr, n);
                            }

                            // this logic below handles cases when multiple overloading methods
                            // are ambiguous, hence comparison between Python and CLR types
                            // is necessary
                            clrConvertedParameterType = null;
                            IntPtr pythonParameterPtrType = IntPtr.Zero;
                            if (_methods.Length > 1)
                            {
                                pythonParameterPtrType = Runtime.PyObject_Type(pythonParameterPtr);
                                Exceptions.Clear();
                                if (pythonParameterPtrType != IntPtr.Zero)
                                {
                                    clrConvertedParameterType = Converter.GetTypeByAlias(pythonParameterPtrType);
                                }
                                Runtime.XDecref(pythonParameterPtrType);
                            }


                            if (clrConvertedParameterType != null)
                            {
                                var parameterTypeMatch = false;
                                if ((clrParameterInfoArray[n].ParameterType != typeof(object)) && (clrParameterInfoArray[n].ParameterType != clrConvertedParameterType))
                                {
                                    IntPtr pythonConvertedParameterPtrType = Converter.GetPythonTypeByAlias(clrParameterInfoArray[n].ParameterType);
                                    pythonParameterPtrType = Runtime.PyObject_Type(pythonParameterPtr);
                                    Exceptions.Clear();
                                    if (pythonParameterPtrType != IntPtr.Zero)
                                    {
                                        if (pythonConvertedParameterPtrType != pythonParameterPtrType)
                                        {
                                            parameterTypeMatch = false;
                                        }
                                        else
                                        {
                                            parameterTypeMatch        = true;
                                            clrConvertedParameterType = clrParameterInfoArray[n].ParameterType;
                                        }
                                    }
                                    if (!parameterTypeMatch)
                                    {
                                        // this takes care of enum values
                                        TypeCode clrParameterTypeCode          = Type.GetTypeCode(clrParameterInfoArray[n].ParameterType);
                                        TypeCode clrConvertedParameterTypeCode = Type.GetTypeCode(clrConvertedParameterType);
                                        if (clrParameterTypeCode == clrConvertedParameterTypeCode)
                                        {
                                            parameterTypeMatch        = true;
                                            clrConvertedParameterType = clrParameterInfoArray[n].ParameterType;
                                        }
                                    }
                                    Runtime.XDecref(pythonParameterPtrType);
                                    if (!parameterTypeMatch)
                                    {
                                        methodParametersPtrArray = null;
                                        break;
                                    }
                                }
                                else
                                {
                                    parameterTypeMatch        = true;
                                    clrConvertedParameterType = clrParameterInfoArray[n].ParameterType;
                                }
                            }
                            else
                            {
                                clrConvertedParameterType = clrParameterInfoArray[n].ParameterType;
                            }

                            if (clrParameterInfoArray[n].IsOut || clrConvertedParameterType.IsByRef)
                            {
                                byRefCount++;
                            }

                            if (!Converter.ToManaged(pythonParameterPtr, clrConvertedParameterType, out pythonManagedParameterPtr, false))
                            {
                                Exceptions.Clear();
                                methodParametersPtrArray = null;
                                break;
                            }
                            if (clrParamsArrayStart == n)
                            {
                                // GetSlice() creates a new reference but GetItem()
                                // returns only a borrow reference.
                                Runtime.XDecref(pythonParameterPtr);
                            }
                            methodParametersPtrArray[n] = pythonParameterPtr;
                        }
                        else
                        {
                            if (defaultParameterList != null)
                            {
                                methodParametersPtrArray[n] = defaultParameterList[n - pythonParameterCount];
                            }
                        }
                    }

                    if (methodParametersPtrArray == null)
                    {
                        continue;
                    }

                    object target = null;
                    if (!methodInfo.IsStatic && inst != IntPtr.Zero)
                    {
                        //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
                        // InvalidCastException: Unable to cast object of type
                        // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
                        var co = ManagedType.GetManagedObject(inst) as CLRObject;

                        // Sanity check: this ensures a graceful exit if someone does
                        // something intentionally wrong like call a non-static method
                        // on the class rather than on an instance of the class.
                        // XXX maybe better to do this before all the other rigmarole.
                        if (co == null)
                        {
                            return(null);
                        }
                        target = co.inst;
                    }

                    return(new Binding(methodInfo, target, methodParametersPtrArray, byRefCount));
                }
            }
            // We weren't able to find a matching method but at least one
            // is a generic method and info is null. That happens when a generic
            // method was not called using the [] syntax. Let's introspect the
            // type of the arguments and use it to construct the correct method.
            if (isGeneric && info == null && methodInfoArray != null)
            {
                Type[]     types = Runtime.PythonArgsToTypeArray(pythonParametersPtr, true);
                MethodInfo mi    = MatchParameters(methodInfoArray, types);
                return(Bind(inst, pythonParametersPtr, kw, mi, null));
            }
            return(null);
        }