private static Type GetBaseTypeFromUserType(PythonType curBasePythonType, IList <Type> baseInterfaces, Type curTypeToExtend) { Queue <PythonType> processing = new Queue <PythonType>(); processing.Enqueue(curBasePythonType); do { PythonType walking = processing.Dequeue(); foreach (PythonType dt in walking.BaseTypes) { if (dt.ExtensionType == curTypeToExtend || curTypeToExtend.IsSubclassOf(dt.ExtensionType)) { continue; } if (dt.ExtensionType.IsInterface) { baseInterfaces.Add(dt.ExtensionType); } else if (NewTypeMaker.IsInstanceType(dt.ExtensionType)) { processing.Enqueue(dt); } else if (!dt.IsOldClass) { curTypeToExtend = null; break; } } } while (processing.Count > 0); return(curTypeToExtend); }
public override Type GetTypesToExtend(out IList <Type> interfacesToExtend) { interfacesToExtend = new List <Type>(); foreach (object b in bases) { if (b is OldClass) { continue; } PythonType baseType = b as PythonType; IList <Type> baseTypeInterfaces; baseType.GetTypesToExtend(out baseTypeInterfaces); foreach (Type baseTypeInterface in baseTypeInterfaces) { interfacesToExtend.Add(baseTypeInterface); } } // We dont use type.GetInterfaces() as it contains all the interfaces that are added by NewTypeMaker, // as well as all the interfaces implemented by type.BaseType. Instead, we only want the new set of // interfaces that need to be implemented by the new instance type. Debug.Assert(interfacesToExtend.Count < type.GetInterfaces().Length); // "type" is the instance type used for instances of this type. This will be a type created by NewTypeMaker. Debug.Assert(NewTypeMaker.IsInstanceType(type)); // Its BaseType will the CLI type that needs to be inherited by instance types used by other UserTypes inheriting // from the current UserType. For pure Python types, this will be System.Object. Debug.Assert(!NewTypeMaker.IsInstanceType(type.BaseType)); return(type.BaseType); }
/// <summary> /// Gets a builtin function for the given declaring type and member infos. /// /// Given the same inputs this always returns the same object ensuring there's only 1 builtinfunction /// for each .NET method. /// /// This method takes both a cacheName and a pythonName. The cache name is the real method name. The pythonName /// is the name of the method as exposed to Python. /// </summary> internal static BuiltinFunction /*!*/ GetBuiltinFunction(Type /*!*/ type, string /*!*/ cacheName, string /*!*/ pythonName, FunctionType?funcType, params MemberInfo /*!*/[] /*!*/ mems) { BuiltinFunction res = null; if (mems.Length != 0) { FunctionType ft = funcType ?? GetMethodFunctionType(type, mems); type = GetBaseDeclaringType(type, mems); BuiltinFunctionKey cache = new BuiltinFunctionKey(type, new ReflectionCache.MethodBaseCache(cacheName, GetNonBaseHelperMethodInfos(mems)), ft); lock (_functions) { if (!_functions.TryGetValue(cache, out res)) { if (PythonTypeOps.GetFinalSystemType(type) == type) { IList <MethodInfo> overriddenMethods = NewTypeMaker.GetOverriddenMethods(type, cacheName); if (overriddenMethods.Count > 0) { List <MemberInfo> newMems = new List <MemberInfo>(mems); foreach (MethodInfo mi in overriddenMethods) { newMems.Add(mi); } mems = newMems.ToArray(); } } _functions[cache] = res = BuiltinFunction.MakeMethod(pythonName, ReflectionUtils.GetMethodInfos(mems), type, ft); } } } return(res); }
/// <summary> /// clr.CompileSubclassTypes(assemblyName, *typeDescription) /// /// Provides a helper for creating an assembly which contains pre-generated .NET /// base types for new-style types. /// /// This assembly can then be AddReferenced or put sys.prefix\DLLs and the cached /// types will be used instead of generating the types at runtime. /// /// This function takes the name of the assembly to save to and then an arbitrary /// number of parameters describing the types to be created. Each of those /// parameter can either be a plain type or a sequence of base types. /// /// clr.CompileSubclassTypes(object) -> create a base type for object /// clr.CompileSubclassTypes(object, str, System.Collections.ArrayList) -> create /// base types for both object and ArrayList. /// /// clr.CompileSubclassTypes(object, (object, IComparable)) -> create base types for /// object and an object which implements IComparable. /// /// </summary> public static void CompileSubclassTypes(string /*!*/ assemblyName, params object[] newTypes) { if (assemblyName == null) { throw PythonOps.TypeError("CompileTypes expected str for assemblyName, got NoneType"); } var typesToCreate = new List <PythonTuple>(); foreach (object o in newTypes) { if (o is PythonType) { typesToCreate.Add(PythonTuple.MakeTuple(o)); } else { typesToCreate.Add(PythonTuple.Make(o)); } } NewTypeMaker.SaveNewTypes(assemblyName, typesToCreate); }
protected UserType(string name, Tuple bases, IDictionary <object, object> dict) : base(NewTypeMaker.GetNewType(name, bases, dict)) { List <MethodInfo> ctors = new List <MethodInfo>(); foreach (MethodInfo mi in type.GetMethods()) { if (mi.Name == ReflectedType.MakeNewName) { ctors.Add(mi); } } if (ctors.Count == 0) { throw new NotImplementedException("no MakeNew found"); } ctor = BuiltinFunction.Make(name, ctors.ToArray(), ctors.ToArray(), FunctionType.Function); IAttributesDictionary fastDict = (IAttributesDictionary)dict; this.__name__ = name; this.__module__ = fastDict[SymbolTable.Module]; // should always be present... if (!fastDict.ContainsKey(SymbolTable.Doc)) { fastDict[SymbolTable.Doc] = null; } InitializeUserType(bases, false); this.dict = CreateNamespaceDictionary(dict); AddProtocolWrappers(); }
internal static ReflectedGetterSetter GetReflectedProperty(PropertyTracker pt, MemberGroup allProperties, bool privateBinding) { ReflectedGetterSetter rp; lock (_propertyCache) { if (_propertyCache.TryGetValue(pt, out rp)) { return(rp); } NameType nt = NameType.PythonProperty; MethodInfo getter = FilterProtectedGetterOrSetter(pt.GetGetMethod(true), privateBinding); MethodInfo setter = FilterProtectedGetterOrSetter(pt.GetSetMethod(true), privateBinding); if ((getter != null && PythonHiddenAttribute.IsHidden(getter, true)) || (setter != null && PythonHiddenAttribute.IsHidden(setter, true))) { nt = NameType.Property; } ExtensionPropertyTracker ept = pt as ExtensionPropertyTracker; if (ept == null) { ReflectedPropertyTracker rpt = pt as ReflectedPropertyTracker; Debug.Assert(rpt != null); if (PythonBinder.IsExtendedType(pt.DeclaringType) || PythonHiddenAttribute.IsHidden(rpt.Property, true)) { nt = NameType.Property; } if (pt.GetIndexParameters().Length == 0) { List <MethodInfo> getters = new List <MethodInfo>(); List <MethodInfo> setters = new List <MethodInfo>(); IList <ExtensionPropertyTracker> overriddenProperties = NewTypeMaker.GetOverriddenProperties((getter ?? setter).DeclaringType, pt.Name); foreach (ExtensionPropertyTracker tracker in overriddenProperties) { MethodInfo method = tracker.GetGetMethod(privateBinding); if (method != null) { getters.Add(method); } method = tracker.GetSetMethod(privateBinding); if (method != null) { setters.Add(method); } } foreach (PropertyTracker propTracker in allProperties) { MethodInfo method = propTracker.GetGetMethod(privateBinding); if (method != null) { getters.Add(method); } method = propTracker.GetSetMethod(privateBinding); if (method != null) { setters.Add(method); } } rp = new ReflectedProperty(rpt.Property, getters.ToArray(), setters.ToArray(), nt); } else { rp = new ReflectedIndexer(((ReflectedPropertyTracker)pt).Property, NameType.Property, privateBinding); } } else { rp = new ReflectedExtensionProperty(new ExtensionPropertyInfo(pt.DeclaringType, getter ?? setter), nt); } _propertyCache[pt] = rp; return(rp); } }
/// <summary> /// "bases" contains a set of PythonTypes. These can include types defined in Python (say cpy1, cpy2), /// CLI types (say cCLI1, cCLI2), and CLI interfaces (say iCLI1, iCLI2). Here are some /// examples of how this works: /// /// (bases) => baseType, {interfaceTypes} /// /// (cpy1) => System.Object, {} /// (cpy1, cpy2) => System.Object, {} /// (cpy1, cCLI1, iCLI1, iCLI2) => cCLI1, {iCLI1, iCLI2} /// [some type that satisfies the line above] => /// cCLI1, {iCLI1, iCLI2} /// (cCLI1, cCLI2) => error /// </summary> public static NewTypeInfo GetTypeInfo(string typeName, PythonTuple bases) { List <Type> interfaceTypes = new List <Type>(); Type baseCLIType = typeof(object); // Pure Python object instances inherit from System.Object PythonType basePythonType = null; foreach (PythonType curBasePythonType in GetPythonTypes(typeName, bases)) { // discover the initial base/interfaces IList <Type> baseInterfaces = ReflectionUtils.EmptyTypes; Type curTypeToExtend = curBasePythonType.ExtensionType; if (curBasePythonType.ExtensionType.IsInterface) { baseInterfaces = new Type[] { curTypeToExtend }; curTypeToExtend = typeof(object); } else if (NewTypeMaker.IsInstanceType(curTypeToExtend)) { baseInterfaces = new List <Type>(); curTypeToExtend = GetBaseTypeFromUserType(curBasePythonType, baseInterfaces, curTypeToExtend.BaseType); } if (curTypeToExtend == null || typeof(BuiltinFunction).IsAssignableFrom(curTypeToExtend) || typeof(PythonFunction).IsAssignableFrom(curTypeToExtend)) { throw PythonOps.TypeError(typeName + ": {0} is not an acceptable base type", curBasePythonType.Name); } if (curTypeToExtend.ContainsGenericParameters) { throw PythonOps.TypeError(typeName + ": cannot inhert from open generic instantiation {0}. Only closed instantiations are supported.", curBasePythonType); } foreach (Type interfaceType in baseInterfaces) { if (interfaceType.ContainsGenericParameters) { throw PythonOps.TypeError(typeName + ": cannot inhert from open generic instantiation {0}. Only closed instantiations are supported.", interfaceType); } // collecting all the interfaces because we override them all. interfaceTypes.Add(interfaceType); } // if we're not extending something already in our existing base classes type hierarchy // then we better be in some esoteric __slots__ situation if (!baseCLIType.IsSubclassOf(curTypeToExtend)) { if (baseCLIType != typeof(object) && baseCLIType != curTypeToExtend && (!baseCLIType.IsDefined(typeof(DynamicBaseTypeAttribute), false) && !curTypeToExtend.IsSubclassOf(baseCLIType))) { throw PythonOps.TypeError( typeName + ": can only extend one CLI or builtin type, not both {0} (for {1}) and {2} (for {3})", baseCLIType.FullName, basePythonType, curTypeToExtend.FullName, curBasePythonType); } // we have a new base type baseCLIType = curTypeToExtend; basePythonType = curBasePythonType; } } return(new NewTypeInfo(baseCLIType, interfaceTypes.Count == 0 ? ReflectionUtils.EmptyTypes : interfaceTypes.ToArray())); }