PageRenderTime 49ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/williamybs/uidipythontool
C# | 186 lines | 106 code | 23 blank | 57 comment | 31 complexity | 15584cefa6657a3bcaf6cfc82877ff44 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.Collections.Generic;
  16. using System.Diagnostics;
  17. using IronPython.Runtime.Operations;
  18. using System;
  19. namespace IronPython.Runtime.Types {
  20. /// <summary>
  21. /// Calculates the method resolution order for a Python class
  22. /// the rules are:
  23. /// If A is a subtype of B, then A has precedence (A >B)
  24. /// If C appears before D in the list of bases then C > D
  25. /// If E > F in one __mro__ then E > F in all __mro__'s for our subtype
  26. ///
  27. /// class A(object): pass
  28. /// class B(object): pass
  29. /// class C(B): pass
  30. /// class N(A,B,C): pass # illegal
  31. ///
  32. /// This is because:
  33. /// C.__mro__ == (C, B, object)
  34. /// N.__mro__ == (N, A, B, C, object)
  35. /// which would conflict, but:
  36. ///
  37. /// N(B,A) is ok (N, B, a, object)
  38. /// N(C, B, A) is ok (N, C, B, A, object)
  39. ///
  40. /// Calculates a C3 MRO as described in "The Python 2.3 Method Resolution Order"
  41. /// plus support for old-style classes.
  42. ///
  43. /// We build up a list of our base classes MRO's plus our base classes themselves.
  44. /// We go through the list in order. Look at the 1st class in the current list, and
  45. /// if it's not the non-first class in any other list then remove it from all the lists
  46. /// and append it to the mro. Otherwise continue to the next list. If all the classes at
  47. /// the start are no-good then the MRO is bad and we throw.
  48. ///
  49. /// For old-style classes if the old-style class is the only one in the list of bases add
  50. /// it as a depth-first old-style MRO, otherwise compute a new-style mro for all the classes
  51. /// and use that.
  52. /// </summary>
  53. static class Mro {
  54. public static List<PythonType> Calculate(PythonType startingType, IList<PythonType> bases) {
  55. return Calculate(startingType, new List<PythonType>(bases), false);
  56. }
  57. /// <summary>
  58. /// </summary>
  59. public static List<PythonType> Calculate(PythonType startingType, IList<PythonType> baseTypes, bool forceNewStyle) {
  60. List<PythonType> bases = new List<PythonType>();
  61. foreach (PythonType dt in baseTypes) bases.Add(dt);
  62. if (bases.Contains(startingType)) {
  63. throw PythonOps.TypeError("a __bases__ item causes an inheritance cycle ({0})", startingType.Name);
  64. }
  65. List<PythonType> mro = new List<PythonType>();
  66. mro.Add(startingType);
  67. if (bases.Count != 0) {
  68. List<IList<PythonType>> mroList = new List<IList<PythonType>>();
  69. // build up the list - it contains the MRO of all our
  70. // bases as well as the bases themselves in the order in
  71. // which they appear.
  72. int oldSytleCount = 0;
  73. foreach (PythonType type in bases) {
  74. if (type.IsOldClass) oldSytleCount++;
  75. }
  76. foreach (PythonType dt in bases) {
  77. if (!dt.IsOldClass) {
  78. mroList.Add(TupleToList(dt.ResolutionOrder));
  79. } else if (oldSytleCount == 1 && !forceNewStyle) {
  80. mroList.Add(GetOldStyleMro(dt));
  81. } else {
  82. mroList.Add(GetNewStyleMro(dt));
  83. }
  84. }
  85. mroList.Add(TupleToList(bases));
  86. for (; ; ) {
  87. bool removed = false, sawNonZero = false;
  88. // now that we have our list, look for good heads
  89. PythonType lastHead = null;
  90. for (int i = 0; i < mroList.Count; i++) {
  91. if (mroList[i].Count == 0) continue; // we've removed everything from this list.
  92. sawNonZero = true;
  93. PythonType head = lastHead = mroList[i][0];
  94. // see if we're in the tail of any other lists...
  95. bool inTail = false;
  96. for (int j = 0; j < mroList.Count; j++) {
  97. if (mroList[j].Count != 0 && !mroList[j][0].Equals(head) && mroList[j].Contains(head)) {
  98. inTail = true;
  99. break;
  100. }
  101. }
  102. if (!inTail) {
  103. if (mro.Contains(head)) {
  104. throw PythonOps.TypeError("a __bases__ item causes an inheritance cycle");
  105. }
  106. // add it to the linearization, and remove
  107. // it from our lists
  108. mro.Add(head);
  109. for (int j = 0; j < mroList.Count; j++) {
  110. mroList[j].Remove(head);
  111. }
  112. removed = true;
  113. break;
  114. }
  115. }
  116. if (!sawNonZero) break;
  117. if (!removed) {
  118. // we've iterated through the list once w/o removing anything
  119. PythonType other = null;
  120. string error = String.Format("Cannot create a consistent method resolution\norder (MRO) for bases {0}", lastHead.Name);
  121. for (int i = 0; i < mroList.Count; i++) {
  122. if (mroList[i].Count != 0 && !mroList[i][0].Equals(lastHead)) {
  123. other = mroList[i][0];
  124. error += ", ";
  125. error += other.Name;
  126. }
  127. }
  128. throw PythonOps.TypeError(error);
  129. }
  130. }
  131. }
  132. return mro;
  133. }
  134. private static IList<PythonType> TupleToList(IList<PythonType> t) {
  135. return new List<PythonType>(t);
  136. }
  137. private static IList<PythonType> GetOldStyleMro(PythonType oldStyleType) {
  138. List<PythonType> res = new List<PythonType>();
  139. GetOldStyleMroWorker(oldStyleType, res);
  140. return res;
  141. }
  142. private static void GetOldStyleMroWorker(PythonType curType, List<PythonType> res) {
  143. PythonType dt = curType as PythonType;
  144. Debug.Assert(dt != null);
  145. if (!res.Contains(curType)) {
  146. res.Add(curType);
  147. foreach (PythonType baseDt in dt.BaseTypes) {
  148. GetOldStyleMroWorker(baseDt, res);
  149. }
  150. }
  151. }
  152. private static IList<PythonType> GetNewStyleMro(PythonType oldStyleType) {
  153. PythonType dt = oldStyleType as PythonType;
  154. Debug.Assert(dt != null);
  155. List<PythonType> res = new List<PythonType>();
  156. res.Add(oldStyleType);
  157. foreach (PythonType baseDt in dt.BaseTypes) {
  158. res.AddRange(TupleToList(Calculate(baseDt, baseDt.BaseTypes, true)));
  159. }
  160. return res;
  161. }
  162. }
  163. }