PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython/Runtime/Types/NewTypeInfo.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 181 lines | 111 code | 28 blank | 42 comment | 37 complexity | 0388d19c4d43fe96304a162ab1c9e9b6 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using IronPython.Runtime.Operations;
  18. namespace IronPython.Runtime.Types {
  19. /// <summary>
  20. /// TypeInfo captures the minimal CLI information required by NewTypeMaker for a Python object
  21. /// that inherits from a CLI type.
  22. /// </summary>
  23. internal class NewTypeInfo {
  24. // The CLI base-type.
  25. private readonly Type _baseType;
  26. private readonly IList<Type> _interfaceTypes;
  27. private Nullable<int> _hash;
  28. public NewTypeInfo(Type baseType, IList<Type> interfaceTypes) {
  29. _baseType = baseType;
  30. _interfaceTypes = interfaceTypes;
  31. }
  32. /// <summary>
  33. /// "bases" contains a set of PythonTypes. These can include types defined in Python (say cpy1, cpy2),
  34. /// CLI types (say cCLI1, cCLI2), and CLI interfaces (say iCLI1, iCLI2). Here are some
  35. /// examples of how this works:
  36. ///
  37. /// (bases) => baseType, {interfaceTypes}
  38. ///
  39. /// (cpy1) => System.Object, {}
  40. /// (cpy1, cpy2) => System.Object, {}
  41. /// (cpy1, cCLI1, iCLI1, iCLI2) => cCLI1, {iCLI1, iCLI2}
  42. /// [some type that satisfies the line above] =>
  43. /// cCLI1, {iCLI1, iCLI2}
  44. /// (cCLI1, cCLI2) => error
  45. /// </summary>
  46. public static NewTypeInfo GetTypeInfo(string typeName, PythonTuple bases) {
  47. List<Type> interfaceTypes = new List<Type>();
  48. Type baseCLIType = typeof(object); // Pure Python object instances inherit from System.Object
  49. PythonType basePythonType = null;
  50. foreach (PythonType curBasePythonType in GetPythonTypes(typeName, bases)) {
  51. // discover the initial base/interfaces
  52. IList<Type> baseInterfaces = Type.EmptyTypes;
  53. Type curTypeToExtend = curBasePythonType.ExtensionType;
  54. if (curBasePythonType.ExtensionType.IsInterface) {
  55. baseInterfaces = new Type[] { curTypeToExtend };
  56. curTypeToExtend = typeof(object);
  57. } else if (NewTypeMaker.IsInstanceType(curTypeToExtend)) {
  58. baseInterfaces = new List<Type>();
  59. curTypeToExtend = GetBaseTypeFromUserType(curBasePythonType, baseInterfaces, curTypeToExtend.BaseType);
  60. }
  61. if (curTypeToExtend == null || typeof(BuiltinFunction).IsAssignableFrom(curTypeToExtend) || typeof(PythonFunction).IsAssignableFrom(curTypeToExtend))
  62. throw PythonOps.TypeError(typeName + ": {0} is not an acceptable base type", curBasePythonType.Name);
  63. if (curTypeToExtend.ContainsGenericParameters)
  64. throw PythonOps.TypeError(typeName + ": cannot inhert from open generic instantiation {0}. Only closed instantiations are supported.", curBasePythonType);
  65. foreach (Type interfaceType in baseInterfaces) {
  66. if (interfaceType.ContainsGenericParameters)
  67. throw PythonOps.TypeError(typeName + ": cannot inhert from open generic instantiation {0}. Only closed instantiations are supported.", interfaceType);
  68. // collecting all the interfaces because we override them all.
  69. interfaceTypes.Add(interfaceType);
  70. }
  71. // if we're not extending something already in our existing base classes type hierarchy
  72. // then we better be in some esoteric __slots__ situation
  73. if (!baseCLIType.IsSubclassOf(curTypeToExtend)) {
  74. if (baseCLIType != typeof(object) && baseCLIType != curTypeToExtend &&
  75. (!baseCLIType.IsDefined(typeof(DynamicBaseTypeAttribute), false) && !curTypeToExtend.IsSubclassOf(baseCLIType))) {
  76. throw PythonOps.TypeError(
  77. typeName + ": can only extend one CLI or builtin type, not both {0} (for {1}) and {2} (for {3})",
  78. baseCLIType.FullName,
  79. basePythonType,
  80. curTypeToExtend.FullName,
  81. curBasePythonType);
  82. }
  83. // we have a new base type
  84. baseCLIType = curTypeToExtend;
  85. basePythonType = curBasePythonType;
  86. }
  87. }
  88. return new NewTypeInfo(baseCLIType, interfaceTypes.Count == 0 ? Type.EmptyTypes : interfaceTypes.ToArray());
  89. }
  90. /// <summary>
  91. /// Filters out old-classes and throws if any non-types are included, returning a
  92. /// yielding the remaining PythonType objects.
  93. /// </summary>
  94. private static IEnumerable<PythonType> GetPythonTypes(string typeName, ICollection<object> bases) {
  95. foreach (object curBaseType in bases) {
  96. PythonType curBasePythonType = curBaseType as PythonType;
  97. if (curBasePythonType == null) {
  98. if (curBaseType is OldClass)
  99. continue;
  100. throw PythonOps.TypeError(typeName + ": unsupported base type for new-style class " + curBaseType);
  101. }
  102. yield return curBasePythonType;
  103. }
  104. }
  105. private static Type GetBaseTypeFromUserType(PythonType curBasePythonType, IList<Type> baseInterfaces, Type curTypeToExtend) {
  106. Queue<PythonType> processing = new Queue<PythonType>();
  107. processing.Enqueue(curBasePythonType);
  108. do {
  109. PythonType walking = processing.Dequeue();
  110. foreach (PythonType dt in walking.BaseTypes) {
  111. if (dt.ExtensionType == curTypeToExtend || curTypeToExtend.IsSubclassOf(dt.ExtensionType)) continue;
  112. if (dt.ExtensionType.IsInterface) {
  113. baseInterfaces.Add(dt.ExtensionType);
  114. } else if (NewTypeMaker.IsInstanceType(dt.ExtensionType)) {
  115. processing.Enqueue(dt);
  116. } else if (!dt.IsOldClass) {
  117. curTypeToExtend = null;
  118. break;
  119. }
  120. }
  121. } while (processing.Count > 0);
  122. return curTypeToExtend;
  123. }
  124. public Type BaseType {
  125. get { return _baseType; }
  126. }
  127. public IList<Type> InterfaceTypes {
  128. get { return _interfaceTypes; }
  129. }
  130. public override int GetHashCode() {
  131. if (_hash == null) {
  132. int hashCode = _baseType.GetHashCode();
  133. for (int i = 0; i < _interfaceTypes.Count; i++) {
  134. hashCode ^= _interfaceTypes[i].GetHashCode();
  135. }
  136. _hash = hashCode;
  137. }
  138. return _hash.Value;
  139. }
  140. public override bool Equals(object obj) {
  141. NewTypeInfo other = obj as NewTypeInfo;
  142. if (other == null) return false;
  143. if (_baseType.Equals(other._baseType) &&
  144. _interfaceTypes.Count == other._interfaceTypes.Count) {
  145. for (int i = 0; i < _interfaceTypes.Count; i++) {
  146. if (!_interfaceTypes[i].Equals(other._interfaceTypes[i])) return false;
  147. }
  148. return true;
  149. }
  150. return false;
  151. }
  152. }
  153. }