Ejemplo n.º 1
0
        private static ClassInfo GetClassInfo(Type type)
        {
            var         ci      = new ClassInfo();
            var         methods = new Hashtable();
            ArrayList   list;
            MethodInfo  meth;
            ManagedType ob;
            string      name;
            object      item;
            Type        tp;
            int         i, n;

            MemberInfo[] info  = type.GetMembers(BindingFlags);
            var          local = new Hashtable();
            var          items = new ArrayList();
            MemberInfo   m;

            // Loop through once to find out which names are declared
            for (i = 0; i < info.Length; i++)
            {
                m = info[i];
                if (m.DeclaringType == type)
                {
                    local[m.Name] = 1;
                }
            }

            // only [Flags] enums support bitwise operations
            if (type.IsEnum && type.IsFlagsEnum())
            {
                var opsImpl = typeof(EnumOps <>).MakeGenericType(type);
                foreach (var op in opsImpl.GetMethods(OpsHelper.BindingFlags))
                {
                    local[op.Name] = 1;
                }
                info = info.Concat(opsImpl.GetMethods(OpsHelper.BindingFlags)).ToArray();
            }

            // Now again to filter w/o losing overloaded member info
            for (i = 0; i < info.Length; i++)
            {
                m = info[i];
                if (local[m.Name] != null)
                {
                    items.Add(m);
                }
            }

            if (type.IsInterface)
            {
                // Interface inheritance seems to be a different animal:
                // more contractual, less structural.  Thus, a Type that
                // represents an interface that inherits from another
                // interface does not return the inherited interface's
                // methods in GetMembers. For example ICollection inherits
                // from IEnumerable, but ICollection's GetMemebers does not
                // return GetEnumerator.
                //
                // Not sure if this is the correct way to fix this, but it
                // seems to work. Thanks to Bruce Dodson for the fix.

                Type[] inheritedInterfaces = type.GetInterfaces();

                for (i = 0; i < inheritedInterfaces.Length; ++i)
                {
                    Type         inheritedType = inheritedInterfaces[i];
                    MemberInfo[] imembers      = inheritedType.GetMembers(BindingFlags);
                    for (n = 0; n < imembers.Length; n++)
                    {
                        m = imembers[n];
                        if (local[m.Name] == null)
                        {
                            items.Add(m);
                        }
                    }
                }

                // All interface implementations inherit from Object,
                // but GetMembers don't return them either.
                var objFlags = BindingFlags.Public | BindingFlags.Instance;
                foreach (var mi in typeof(object).GetMembers(objFlags))
                {
                    if (local[mi.Name] == null)
                    {
                        items.Add(mi);
                    }
                }
            }

            for (i = 0; i < items.Count; i++)
            {
                var mi = (MemberInfo)items[i];

                switch (mi.MemberType)
                {
                case MemberTypes.Method:
                    meth = (MethodInfo)mi;
                    if (!ShouldBindMethod(meth))
                    {
                        continue;
                    }
                    name = meth.Name;
                    item = methods[name];
                    if (item == null)
                    {
                        item = methods[name] = new ArrayList();
                    }
                    list = (ArrayList)item;
                    list.Add(meth);
                    continue;

                case MemberTypes.Property:
                    var pi = (PropertyInfo)mi;

                    if (!ShouldBindProperty(pi))
                    {
                        continue;
                    }

                    // Check for indexer
                    ParameterInfo[] args = pi.GetIndexParameters();
                    if (args.GetLength(0) > 0)
                    {
                        Indexer idx = ci.indexer;
                        if (idx == null)
                        {
                            ci.indexer = new Indexer();
                            idx        = ci.indexer;
                        }
                        idx.AddProperty(pi);
                        continue;
                    }

                    ob = new PropertyObject(pi);
                    ci.members[pi.Name] = ob;
                    continue;

                case MemberTypes.Field:
                    var fi = (FieldInfo)mi;
                    if (!ShouldBindField(fi))
                    {
                        continue;
                    }
                    ob = new FieldObject(fi);
                    ci.members[mi.Name] = ob;
                    continue;

                case MemberTypes.Event:
                    var ei = (EventInfo)mi;
                    if (!ShouldBindEvent(ei))
                    {
                        continue;
                    }
                    ob = new EventObject(ei);
                    ci.members[ei.Name] = ob;
                    continue;

                case MemberTypes.NestedType:
                    tp = (Type)mi;
                    if (!(tp.IsNestedPublic || tp.IsNestedFamily ||
                          tp.IsNestedFamORAssem))
                    {
                        continue;
                    }
                    // Note the given instance might be uninitialized
                    ob = GetClass(tp);
                    if (ob.pyHandle == IntPtr.Zero && ob is ClassObject)
                    {
                        ob.pyHandle = ob.tpHandle = TypeManager.GetOrCreateClass(tp).Handle;
                    }
                    Debug.Assert(ob.pyHandle != IntPtr.Zero);
                    // GetClass returns a Borrowed ref. ci.members owns the reference.
                    ob.IncrRefCount();
                    ci.members[mi.Name] = ob;
                    continue;
                }
            }

            IDictionaryEnumerator iter = methods.GetEnumerator();

            while (iter.MoveNext())
            {
                name = (string)iter.Key;
                list = (ArrayList)iter.Value;

                var mlist = (MethodInfo[])list.ToArray(typeof(MethodInfo));

                ob = new MethodObject(type, name, mlist);
                ci.members[name] = ob;
                if (mlist.Any(OperatorMethod.IsOperatorMethod))
                {
                    string pyName        = OperatorMethod.GetPyMethodName(name);
                    string pyNameReverse = OperatorMethod.ReversePyMethodName(pyName);
                    OperatorMethod.FilterMethods(mlist, out var forwardMethods, out var reverseMethods);
                    // Only methods where the left operand is the declaring type.
                    if (forwardMethods.Length > 0)
                    {
                        ci.members[pyName] = new MethodObject(type, name, forwardMethods);
                    }
                    // Only methods where only the right operand is the declaring type.
                    if (reverseMethods.Length > 0)
                    {
                        ci.members[pyNameReverse] = new MethodObject(type, name, reverseMethods);
                    }
                }
            }

            if (ci.indexer == null && type.IsClass)
            {
                // Indexer may be inherited.
                var parent = type.BaseType;
                while (parent != null && ci.indexer == null)
                {
                    foreach (var prop in parent.GetProperties())
                    {
                        var args = prop.GetIndexParameters();
                        if (args.GetLength(0) > 0)
                        {
                            ci.indexer = new Indexer();
                            ci.indexer.AddProperty(prop);
                            break;
                        }
                    }
                    parent = parent.BaseType;
                }
            }

            return(ci);
        }
Ejemplo n.º 2
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;

            var kwargDict = new Dictionary <string, IntPtr>();

            if (kw != IntPtr.Zero)
            {
                var    pynkwargs = (int)Runtime.PyDict_Size(kw);
                IntPtr keylist   = Runtime.PyDict_Keys(kw);
                IntPtr valueList = Runtime.PyDict_Values(kw);
                for (int i = 0; i < pynkwargs; ++i)
                {
                    var keyStr = Runtime.GetManagedString(Runtime.PyList_GetItem(new BorrowedReference(keylist), i));
                    kwargDict[keyStr] = Runtime.PyList_GetItem(new BorrowedReference(valueList), i).DangerousGetAddress();
                }
                Runtime.XDecref(keylist);
                Runtime.XDecref(valueList);
            }

            var pynargs   = (int)Runtime.PyTuple_Size(args);
            var isGeneric = false;

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

            var argMatchedMethods = new List <MatchedMethod>(_methods.Length);

            // TODO: Clean up
            foreach (MethodBase mi in _methods)
            {
                if (mi.IsGenericMethod)
                {
                    isGeneric = true;
                }
                ParameterInfo[] pi = mi.GetParameters();
                ArrayList       defaultArgList;
                bool            paramsArray;
                int             kwargsMatched;
                int             defaultsNeeded;
                bool            isOperator = OperatorMethod.IsOperatorMethod(mi);
                int             clrnargs   = pi.Length;
                // Binary operator methods will have 2 CLR args but only one Python arg
                // (unary operators will have 1 less each), since Python operator methods are bound.
                isOperator = isOperator && pynargs == clrnargs - 1;
                if (!MatchesArgumentCount(pynargs, pi, kwargDict, out paramsArray, out defaultArgList, out kwargsMatched, out defaultsNeeded) && !isOperator)
                {
                    continue;
                }
                // Preprocessing pi to remove either the first or second argument.
                bool isReverse = isOperator && OperatorMethod.IsReverse((MethodInfo)mi);  // Only cast if isOperator.
                if (isOperator && !isReverse)
                {
                    // The first Python arg is the right operand, while the bound instance is the left.
                    // We need to skip the first (left operand) CLR argument.
                    pi = pi.Skip(1).ToArray();
                }
                else if (isOperator && isReverse)
                {
                    // The first Python arg is the left operand.
                    // We need to take the first CLR argument.
                    pi = pi.Take(1).ToArray();
                }
                var outs  = 0;
                var margs = TryConvertArguments(pi, paramsArray, args, pynargs, kwargDict, defaultArgList,
                                                needsResolution: _methods.Length > 1, // If there's more than one possible match.
                                                outs: out outs);
                if (margs == null)
                {
                    continue;
                }
                if (isOperator)
                {
                    if (inst != IntPtr.Zero)
                    {
                        if (ManagedType.GetManagedObject(inst) is CLRObject co)
                        {
                            bool isUnary = pynargs == 0;
                            // Postprocessing to extend margs.
                            var margsTemp = isUnary ? new object[1] : new object[2];
                            // If reverse, the bound instance is the right operand.
                            int boundOperandIndex = isReverse ? 1 : 0;
                            // If reverse, the passed instance is the left operand.
                            int passedOperandIndex = isReverse ? 0 : 1;
                            margsTemp[boundOperandIndex] = co.inst;
                            if (!isUnary)
                            {
                                margsTemp[passedOperandIndex] = margs[0];
                            }
                            margs = margsTemp;
                        }
                        else
                        {
                            break;
                        }
                    }
                }


                var matchedMethod = new MatchedMethod(kwargsMatched, defaultsNeeded, margs, outs, mi);
                argMatchedMethods.Add(matchedMethod);
            }
            if (argMatchedMethods.Count > 0)
            {
                var bestKwargMatchCount    = argMatchedMethods.Max(x => x.KwargsMatched);
                var fewestDefaultsRequired = argMatchedMethods.Where(x => x.KwargsMatched == bestKwargMatchCount).Min(x => x.DefaultsNeeded);

                int bestCount      = 0;
                int bestMatchIndex = -1;

                for (int index = 0; index < argMatchedMethods.Count; index++)
                {
                    var testMatch = argMatchedMethods[index];
                    if (testMatch.DefaultsNeeded == fewestDefaultsRequired && testMatch.KwargsMatched == bestKwargMatchCount)
                    {
                        bestCount++;
                        if (bestMatchIndex == -1)
                        {
                            bestMatchIndex = index;
                        }
                    }
                }

                if (bestCount > 1 && fewestDefaultsRequired > 0)
                {
                    // Best effort for determining method to match on gives multiple possible
                    // matches and we need at least one default argument - bail from this point
                    return(null);
                }

                // If we're here either:
                //      (a) There is only one best match
                //      (b) There are multiple best matches but none of them require
                //          default arguments
                // in the case of (a) we're done by default. For (b) regardless of which
                // method we choose, all arguments are specified _and_ can be converted
                // from python to C# so picking any will suffice
                MatchedMethod bestMatch = argMatchedMethods[bestMatchIndex];
                var           margs     = bestMatch.ManagedArgs;
                var           outs      = bestMatch.Outs;
                var           mi        = bestMatch.Method;

                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);
        }
Ejemplo n.º 3
0
        internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo)
        {
            // Relevant function variables used post conversion
            var     isGeneric = false;
            Binding bindingUsingImplicitConversion = null;

            // If we have KWArgs create dictionary and collect them
            Dictionary <string, IntPtr> kwArgDict = null;

            if (kw != IntPtr.Zero)
            {
                var pyKwArgsCount = (int)Runtime.PyDict_Size(kw);
                kwArgDict = new Dictionary <string, IntPtr>(pyKwArgsCount);
                IntPtr keylist   = Runtime.PyDict_Keys(kw);
                IntPtr valueList = Runtime.PyDict_Values(kw);
                for (int i = 0; i < pyKwArgsCount; ++i)
                {
                    var keyStr = Runtime.GetManagedString(Runtime.PyList_GetItem(new BorrowedReference(keylist), i));
                    kwArgDict[keyStr] = Runtime.PyList_GetItem(new BorrowedReference(valueList), i).DangerousGetAddress();
                }
                Runtime.XDecref(keylist);
                Runtime.XDecref(valueList);
            }

            // Fetch our methods we are going to attempt to match and bind too.
            var methods = info == null?GetMethods()
                              : new List <MethodInformation>(1)
            {
                new MethodInformation(info, info.GetParameters())
            };

            foreach (var methodInformation in methods)
            {
                // Relevant method variables
                var mi = methodInformation.MethodBase;
                var pi = methodInformation.ParameterInfo;

                isGeneric = mi.IsGenericMethod;
                int pyArgCount = (int)Runtime.PyTuple_Size(args);


                // Special case for operators
                bool isOperator = OperatorMethod.IsOperatorMethod(mi);
                // Binary operator methods will have 2 CLR args but only one Python arg
                // (unary operators will have 1 less each), since Python operator methods are bound.
                isOperator = isOperator && pyArgCount == pi.Length - 1;
                bool isReverse = isOperator && OperatorMethod.IsReverse((MethodInfo)mi);  // Only cast if isOperator.
                if (isReverse && OperatorMethod.IsComparisonOp((MethodInfo)mi))
                {
                    continue;  // Comparison operators in Python have no reverse mode.
                }
                // Preprocessing pi to remove either the first or second argument.
                if (isOperator && !isReverse)
                {
                    // The first Python arg is the right operand, while the bound instance is the left.
                    // We need to skip the first (left operand) CLR argument.
                    pi = pi.Skip(1).ToArray();
                }
                else if (isOperator && isReverse)
                {
                    // The first Python arg is the left operand.
                    // We need to take the first CLR argument.
                    pi = pi.Take(1).ToArray();
                }

                // Must be done after IsOperator section
                int clrArgCount = pi.Length;

                if (CheckMethodArgumentsMatch(clrArgCount,
                                              pyArgCount,
                                              kwArgDict,
                                              pi,
                                              out bool paramsArray,
                                              out int arrayStart,
                                              out ArrayList defaultArgList))
                {
                    var outs  = 0;
                    var margs = new object[clrArgCount];

                    arrayStart = paramsArray ? pi.Length - 1 : -1;
                    var usedImplicitConversion = false;

                    // Conversion loop for each parameter
                    for (int paramIndex = 0; paramIndex < clrArgCount; paramIndex++)
                    {
                        IntPtr op        = IntPtr.Zero;     // Python object to be converted; not yet set
                        var    parameter = pi[paramIndex];  // Clr parameter we are targeting
                        object arg;                         // Python -> Clr argument

                        // Check our KWargs for this parameter
                        bool hasNamedParam  = kwArgDict == null ? false : kwArgDict.TryGetValue(parameter.Name, out op);
                        bool isNewReference = false;

                        // Check if we are going to use default
                        if (paramIndex >= pyArgCount && !(hasNamedParam || (paramsArray && paramIndex == arrayStart)))
                        {
                            if (defaultArgList != null)
                            {
                                margs[paramIndex] = defaultArgList[paramIndex - pyArgCount];
                            }

                            continue;
                        }

                        // At this point, if op is IntPtr.Zero we don't have a KWArg and are not using default
                        if (op == IntPtr.Zero)
                        {
                            if (arrayStart == paramIndex)
                            {
                                op = HandleParamsArray(args, arrayStart, pyArgCount, out isNewReference);
                            }
                            else
                            {
                                op = Runtime.PyTuple_GetItem(args, paramIndex);
                            }
                        }

                        // this logic below handles cases when multiple overloading methods
                        // are ambiguous, hence comparison between Python and CLR types
                        // is necessary
                        Type   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 ((parameter.ParameterType != typeof(object)) && (parameter.ParameterType != clrtype))
                            {
                                IntPtr pytype = Converter.GetPythonTypeByAlias(parameter.ParameterType);
                                pyoptype = Runtime.PyObject_Type(op);
                                Exceptions.Clear();
                                if (pyoptype != IntPtr.Zero)
                                {
                                    if (pytype != pyoptype)
                                    {
                                        typematch = false;
                                    }
                                    else
                                    {
                                        typematch = true;
                                        clrtype   = parameter.ParameterType;
                                    }
                                }
                                if (!typematch)
                                {
                                    // this takes care of nullables
                                    var underlyingType = Nullable.GetUnderlyingType(parameter.ParameterType);
                                    if (underlyingType == null)
                                    {
                                        underlyingType = parameter.ParameterType;
                                    }
                                    // this takes care of enum values
                                    TypeCode argtypecode   = Type.GetTypeCode(underlyingType);
                                    TypeCode paramtypecode = Type.GetTypeCode(clrtype);
                                    if (argtypecode == paramtypecode)
                                    {
                                        typematch = true;
                                        clrtype   = parameter.ParameterType;
                                    }
                                    // accepts non-decimal numbers in decimal parameters
                                    if (underlyingType == typeof(decimal))
                                    {
                                        clrtype   = parameter.ParameterType;
                                        typematch = Converter.ToManaged(op, clrtype, out arg, false);
                                    }
                                    // this takes care of implicit conversions
                                    var opImplicit = parameter.ParameterType.GetMethod("op_Implicit", new[] { clrtype });
                                    if (opImplicit != null)
                                    {
                                        usedImplicitConversion = typematch = opImplicit.ReturnType == parameter.ParameterType;
                                        clrtype = parameter.ParameterType;
                                    }
                                }
                                Runtime.XDecref(pyoptype);
                                if (!typematch)
                                {
                                    margs = null;
                                    break;
                                }
                            }
                            else
                            {
                                clrtype = parameter.ParameterType;
                            }
                        }
                        else
                        {
                            clrtype = parameter.ParameterType;
                        }

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

                        if (!Converter.ToManaged(op, clrtype, out arg, false))
                        {
                            Exceptions.Clear();
                            margs = null;
                            break;
                        }

                        if (isNewReference)
                        {
                            // 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);
                        }

                        margs[paramIndex] = arg;
                    }

                    if (margs == null)
                    {
                        continue;
                    }

                    if (isOperator)
                    {
                        if (inst != IntPtr.Zero)
                        {
                            if (ManagedType.GetManagedObject(inst) is CLRObject co)
                            {
                                bool isUnary = pyArgCount == 0;
                                // Postprocessing to extend margs.
                                var margsTemp = isUnary ? new object[1] : new object[2];
                                // If reverse, the bound instance is the right operand.
                                int boundOperandIndex = isReverse ? 1 : 0;
                                // If reverse, the passed instance is the left operand.
                                int passedOperandIndex = isReverse ? 0 : 1;
                                margsTemp[boundOperandIndex] = co.inst;
                                if (!isUnary)
                                {
                                    margsTemp[passedOperandIndex] = margs[0];
                                }
                                margs = margsTemp;
                            }
                            else
                            {
                                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);
        }
Ejemplo n.º 4
0
        internal static IntPtr CreateType(ManagedType impl, Type clrType)
        {
            // Cleanup the type name to get rid of funny nested type names.
            string name = $"clr.{clrType.FullName}";
            int    i    = name.LastIndexOf('+');

            if (i > -1)
            {
                name = name.Substring(i + 1);
            }
            i = name.LastIndexOf('.');
            if (i > -1)
            {
                name = name.Substring(i + 1);
            }

            IntPtr base_   = IntPtr.Zero;
            int    ob_size = ObjectOffset.Size(Runtime.PyTypeType);

            // XXX Hack, use a different base class for System.Exception
            // Python 2.5+ allows new style class exceptions but they *must*
            // subclass BaseException (or better Exception).
            if (typeof(Exception).IsAssignableFrom(clrType))
            {
                ob_size = ObjectOffset.Size(Exceptions.Exception);
            }

            int tp_dictoffset = ob_size + ManagedDataOffsets.ob_dict;

            if (clrType == typeof(Exception))
            {
                base_ = Exceptions.Exception;
            }
            else if (clrType.BaseType != null)
            {
                ClassBase bc = ClassManager.GetClass(clrType.BaseType);
                base_ = bc.pyHandle;
            }

            IntPtr type = AllocateTypeObject(name, Runtime.PyCLRMetaType);

            Marshal.WriteIntPtr(type, TypeOffset.ob_type, Runtime.PyCLRMetaType);
            Runtime.XIncref(Runtime.PyCLRMetaType);

            Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);
            Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);
            Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, (IntPtr)tp_dictoffset);

            // we want to do this after the slot stuff above in case the class itself implements a slot method
            SlotsHolder slotsHolder = CreateSolotsHolder(type);

            InitializeSlots(type, impl.GetType(), slotsHolder);

            if (Marshal.ReadIntPtr(type, TypeOffset.mp_length) == IntPtr.Zero &&
                mp_length_slot.CanAssign(clrType))
            {
                InitializeSlot(type, TypeOffset.mp_length, mp_length_slot.Method, slotsHolder);
            }

            if (!typeof(IEnumerable).IsAssignableFrom(clrType) &&
                !typeof(IEnumerator).IsAssignableFrom(clrType))
            {
                // The tp_iter slot should only be set for enumerable types.
                Marshal.WriteIntPtr(type, TypeOffset.tp_iter, IntPtr.Zero);
            }


            // Only set mp_subscript and mp_ass_subscript for types with indexers
            if (impl is ClassBase cb)
            {
                if (!(impl is ArrayObject))
                {
                    if (cb.indexer == null || !cb.indexer.CanGet)
                    {
                        Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
                    }
                    if (cb.indexer == null || !cb.indexer.CanSet)
                    {
                        Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
                    }
                }
            }
            else
            {
                Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
                Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
            }

            if (base_ != IntPtr.Zero)
            {
                Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
                Runtime.XIncref(base_);
            }

            const int flags = TypeFlags.Default
                              | TypeFlags.Managed
                              | TypeFlags.HeapType
                              | TypeFlags.BaseType
                              | TypeFlags.HaveGC;

            Util.WriteCLong(type, TypeOffset.tp_flags, flags);

            OperatorMethod.FixupSlots(type, clrType);
            // Leverage followup initialization from the Python runtime. Note
            // that the type of the new type must PyType_Type at the time we
            // call this, else PyType_Ready will skip some slot initialization.

            if (Runtime.PyType_Ready(type) != 0)
            {
                throw new PythonException();
            }

            IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
            string mn   = clrType.Namespace ?? "";
            IntPtr mod  = Runtime.PyString_FromString(mn);

            Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod);
            Runtime.XDecref(mod);

            // Hide the gchandle of the implementation in a magic type slot.
            GCHandle gc = impl.AllocGCHandle();

            Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc);

            // Set the handle attributes on the implementing instance.
            impl.tpHandle = type;
            impl.pyHandle = type;

            //DebugUtil.DumpType(type);

            return(type);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Return a precedence value for a particular Type object.
        /// </summary>
        internal static int ArgPrecedence(Type t, MethodInformation mi)
        {
            Type objectType = typeof(object);

            if (t == objectType)
            {
                return(3000);
            }

            if (t.IsAssignableFrom(typeof(PyObject)) && !OperatorMethod.IsOperatorMethod(mi.MethodBase))
            {
                return(-1);
            }

            TypeCode tc = Type.GetTypeCode(t);

            // TODO: Clean up
            switch (tc)
            {
            case TypeCode.Object:
                return(1);

            case TypeCode.UInt64:
                return(10);

            case TypeCode.UInt32:
                return(11);

            case TypeCode.UInt16:
                return(12);

            case TypeCode.Int64:
                return(13);

            case TypeCode.Int32:
                return(14);

            case TypeCode.Int16:
                return(15);

            case TypeCode.Char:
                return(16);

            case TypeCode.SByte:
                return(17);

            case TypeCode.Byte:
                return(18);

            case TypeCode.Single:
                return(20);

            case TypeCode.Double:
                return(21);

            case TypeCode.String:
                return(30);

            case TypeCode.Boolean:
                return(40);
            }

            if (t.IsArray)
            {
                Type e = t.GetElementType();
                if (e == objectType)
                {
                    return(2500);
                }
                return(100 + ArgPrecedence(e, mi));
            }

            return(2000);
        }