[pypy-svn] r4978 - pypy/branch/src-newobjectmodel/pypy/objspace/std
arigo at codespeak.net
arigo at codespeak.net
Sat Jun 5 16:41:33 CEST 2004
Author: arigo
Date: Sat Jun 5 16:41:32 2004
New Revision: 4978
Modified:
pypy/branch/src-newobjectmodel/pypy/objspace/std/mro.py
pypy/branch/src-newobjectmodel/pypy/objspace/std/typeobject.py
pypy/branch/src-newobjectmodel/pypy/objspace/std/typetype.py
Log:
The C3 algorithm to compute the Method Resolution Order now integrated.
Modified: pypy/branch/src-newobjectmodel/pypy/objspace/std/mro.py
==============================================================================
--- pypy/branch/src-newobjectmodel/pypy/objspace/std/mro.py (original)
+++ pypy/branch/src-newobjectmodel/pypy/objspace/std/mro.py Sat Jun 5 16:41:32 2004
@@ -3,68 +3,55 @@
"""
-def MRO(cls):
-
- def register(cls):
- try:
- blocklist = blocking[cls]
- except KeyError:
- blocklist = blocking[cls] = [0]
- prevlist = blocklist
- for base in cls.__bases__:
- prevlist.append(base)
- prevlist = register(base)
- blocklist[0] += 1
- return blocklist
+def mro(cls):
order = []
- blocking = {}
- register(cls)
-
- unblock = [cls]
- while unblock:
- cls = unblock.pop()
- blocklist = blocking[cls]
- assert blocklist[0] > 0
- blocklist[0] -= 1
- if blocklist[0] == 0:
- order.append(cls)
- unblock += blocklist[:0:-1]
-
- if len(order) < len(blocking):
- mro_error(blocking)
+ orderlists = [mro(base) for base in cls.__bases__]
+ orderlists.append([cls] + list(cls.__bases__))
+ while orderlists:
+ for candidatelist in orderlists:
+ candidate = candidatelist[0]
+ if blockinglist(candidate, orderlists) is None:
+ break # good candidate
+ else:
+ mro_error(orderlists) # no candidate found
+ assert candidate not in order
+ order.append(candidate)
+ for i in range(len(orderlists)-1, -1, -1):
+ if orderlists[i][0] == candidate:
+ del orderlists[i][0]
+ if len(orderlists[i]) == 0:
+ del orderlists[i]
return order
-
-def mro_error(blocking):
- # look for a cycle
-
- def find_cycle(cls):
- path.append(cls)
- blocklist = blocking[cls] # raise KeyError when we complete the path
- if blocklist[0] > 0:
- del blocking[cls]
- for cls2 in blocklist[1:]:
- find_cycle(cls2)
- blocking[cls] = blocklist
- del path[-1]
-
- #import pprint; pprint.pprint(blocking)
- path = []
- try:
- for cls in blocking.keys():
- find_cycle(cls)
- except KeyError:
- i = path.index(path[-1])
- names = [cls.__name__ for cls in path[i:]]
- raise TypeError, "Cycle among base classes: " + ' < '.join(names)
- else:
- # should not occur
- raise TypeError, "Cannot create a consistent method resolution order (MRO)"
+def blockinglist(candidate, orderlists):
+ for lst in orderlists:
+ if candidate in lst[1:]:
+ return lst
+ return None # good candidate
+
+def mro_error(orderlists):
+ cycle = []
+ candidate = orderlists[0][0]
+ while candidate not in cycle:
+ cycle.append(candidate)
+ nextblockinglist = blockinglist(candidate, orderlists)
+ candidate = nextblockinglist[0]
+ del cycle[:cycle.index(candidate)]
+ cycle.append(candidate)
+ cycle.reverse()
+ names = [cls.__name__ for cls in cycle]
+ raise TypeError, "Cycle among base classes: " + ' < '.join(names)
+
+
+def mronames(cls):
+ names = [cls.__name__ for cls in mro(cls)]
+ return names
if __name__ == '__main__':
class ex_9:
+ #O = object
class O: pass
class A(O): pass
class B(O): pass
@@ -76,5 +63,11 @@
class K2(D,F,B,E): pass
class K3(D,A): pass
class Z(K1,K2,F,K3): pass
+ class ZM(K1,K2,K3): pass
+ #print ZM.__mro__
- print MRO(ex_9.Z)
+ print 'K1:', mronames(ex_9.K1)
+ print 'K2:', mronames(ex_9.K2)
+ print 'K3:', mronames(ex_9.K3)
+ print mronames(ex_9.ZM)
+ print mronames(ex_9.Z)
Modified: pypy/branch/src-newobjectmodel/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/branch/src-newobjectmodel/pypy/objspace/std/typeobject.py (original)
+++ pypy/branch/src-newobjectmodel/pypy/objspace/std/typeobject.py Sat Jun 5 16:41:32 2004
@@ -10,6 +10,7 @@
w_self.bases_w = bases_w
w_self.dict_w = dict_w
w_self.needs_new_dict = False
+ w_self.mro_w = compute_C3_mro(w_self) # XXX call type(w_self).mro()
if overridetypedef is not None:
w_self.instancetypedef = overridetypedef
else:
@@ -38,23 +39,13 @@
w_self.dict_w['__dict__'] = space.wrap(attrproperty_w('w__dict__'))
elif nd:
w_self.needs_new_dict = True
-
-
-
- def getmro(w_self):
- # XXX this is something that works not too bad right now
- # XXX do the complete mro thing later (see mro.py)
- mro = [w_self]
- for w_parent in w_self.bases_w:
- mro += w_parent.getmro()
- return mro
def lookup(w_self, key):
# note that this doesn't call __get__ on the result at all
# XXX this should probably also return the (parent) class in which
# the attribute was found
space = w_self.space
- for w_class in w_self.getmro():
+ for w_class in w_self.mro_w:
try:
return w_class.dict_w[key]
except KeyError:
@@ -103,7 +94,7 @@
return w_newobject
def issubtype__Type_Type(space, w_type1, w_type2):
- return space.newbool(w_type2 in w_type1.getmro())
+ return space.newbool(w_type2 in w_type1.mro_w)
def repr__Type(space, w_obj):
return space.wrap("<pypy type '%s'>" % w_obj.name) # XXX remove 'pypy'
@@ -133,5 +124,53 @@
# XXX __delattr__
# XXX __hash__ ??
+# ____________________________________________________________
+
+def compute_C3_mro(cls):
+ order = []
+ orderlists = [list(base.mro_w) for base in cls.bases_w]
+ orderlists.append([cls] + cls.bases_w)
+ while orderlists:
+ for candidatelist in orderlists:
+ candidate = candidatelist[0]
+ if mro_blockinglist(candidate, orderlists) is None:
+ break # good candidate
+ else:
+ mro_error(orderlists) # no candidate found
+ assert candidate not in order
+ order.append(candidate)
+ for i in range(len(orderlists)-1, -1, -1):
+ if orderlists[i][0] == candidate:
+ del orderlists[i][0]
+ if len(orderlists[i]) == 0:
+ del orderlists[i]
+ return order
+
+def mro_blockinglist(candidate, orderlists):
+ for lst in orderlists:
+ if candidate in lst[1:]:
+ return lst
+ return None # good candidate
+
+def mro_error(orderlists):
+ cycle = []
+ candidate = orderlists[-1][0]
+ space = candidate.space
+ if candidate in orderlists[-1][1:]:
+ # explicit error message for this specific case
+ raise OperationError(space.w_TypeError,
+ space.wrap("duplicate base class " + candidate.name))
+ while candidate not in cycle:
+ cycle.append(candidate)
+ nextblockinglist = mro_blockinglist(candidate, orderlists)
+ candidate = nextblockinglist[0]
+ del cycle[:cycle.index(candidate)]
+ cycle.append(candidate)
+ cycle.reverse()
+ names = [cls.name for cls in cycle]
+ raise OperationError(space.w_TypeError,
+ space.wrap("cycle among base classes: " + ' < '.join(names)))
+
+# ____________________________________________________________
register_all(vars())
Modified: pypy/branch/src-newobjectmodel/pypy/objspace/std/typetype.py
==============================================================================
--- pypy/branch/src-newobjectmodel/pypy/objspace/std/typetype.py (original)
+++ pypy/branch/src-newobjectmodel/pypy/objspace/std/typetype.py Sat Jun 5 16:41:32 2004
@@ -21,7 +21,7 @@
def descr_get__mro__(space, w_type):
# XXX this should be inside typeobject.py
- return space.newtuple(w_type.getmro())
+ return space.newtuple(w_type.mro_w)
def descr__dict__(space, w_type):
# XXX should return a <dictproxy object>
More information about the Pypy-commit
mailing list