This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

206 rader
5.5 KiB

  1. from copy import deepcopy
  2. from .utils import inline_args
  3. class Tree(object):
  4. def __init__(self, data, children):
  5. self.data = data
  6. self.children = list(children)
  7. def __repr__(self):
  8. return 'Tree(%s, %s)' % (self.data, self.children)
  9. def _pretty_label(self):
  10. return self.data
  11. def _pretty(self, level, indent_str):
  12. if len(self.children) == 1 and not isinstance(self.children[0], Tree):
  13. return [ indent_str*level, self._pretty_label(), '\t', '%s' % self.children[0], '\n']
  14. l = [ indent_str*level, self._pretty_label(), '\n' ]
  15. for n in self.children:
  16. if isinstance(n, Tree):
  17. l += n._pretty(level+1, indent_str)
  18. else:
  19. l += [ indent_str*(level+1), '%s' % n, '\n' ]
  20. return l
  21. def pretty(self, indent_str=' '):
  22. return ''.join(self._pretty(0, indent_str))
  23. def expand_kids_by_index(self, *indices):
  24. for i in sorted(indices, reverse=True): # reverse so that changing tail won't affect indices
  25. kid = self.children[i]
  26. self.children[i:i+1] = kid.children
  27. def __eq__(self, other):
  28. try:
  29. return self.data == other.data and self.children == other.children
  30. except AttributeError:
  31. return False
  32. def __hash__(self):
  33. return hash((self.data, tuple(self.children)))
  34. def find_pred(self, pred):
  35. if pred(self):
  36. yield self
  37. for c in self.children:
  38. if isinstance(c, Tree):
  39. for t in c.find_pred(pred):
  40. yield t
  41. def find_data(self, data):
  42. return self.find_pred(lambda t: t.data == data)
  43. def scan_values(self, pred):
  44. for c in self.children:
  45. if isinstance(c, Tree):
  46. for t in c.scan_values(pred):
  47. yield t
  48. else:
  49. if pred(c):
  50. yield c
  51. def iter_subtrees(self):
  52. visited = set()
  53. q = [self]
  54. while q:
  55. subtree = q.pop()
  56. if id(subtree) in visited:
  57. continue # already been here from another branch
  58. visited.add(id(subtree))
  59. yield subtree
  60. q += [c for c in subtree.children if isinstance(c, Tree)]
  61. def __deepcopy__(self, memo):
  62. return type(self)(self.data, deepcopy(self.children, memo))
  63. def copy(self):
  64. return type(self)(self.data, self.children)
  65. def set(self, data, children):
  66. self.data = data
  67. self.children = children
  68. class Transformer(object):
  69. def _get_func(self, name):
  70. return getattr(self, name)
  71. def transform(self, tree):
  72. items = [self.transform(c) if isinstance(c, Tree) else c for c in tree.children]
  73. try:
  74. f = self._get_func(tree.data)
  75. except AttributeError:
  76. return self.__default__(tree.data, items)
  77. else:
  78. return f(items)
  79. def __default__(self, data, children):
  80. return Tree(data, children)
  81. def __mul__(self, other):
  82. return TransformerChain(self, other)
  83. class TransformerChain(object):
  84. def __init__(self, *transformers):
  85. self.transformers = transformers
  86. def transform(self, tree):
  87. for t in self.transformers:
  88. tree = t.transform(tree)
  89. return tree
  90. def __mul__(self, other):
  91. return TransformerChain(*self.transformers + (other,))
  92. class InlineTransformer(Transformer):
  93. def _get_func(self, name): # use super()._get_func
  94. return inline_args(getattr(self, name)).__get__(self)
  95. class Visitor(object):
  96. def visit(self, tree):
  97. for child in tree.children:
  98. if isinstance(child, Tree):
  99. self.visit(child)
  100. f = getattr(self, tree.data, self.__default__)
  101. f(tree)
  102. return tree
  103. def __default__(self, tree):
  104. pass
  105. class Visitor_NoRecurse(Visitor):
  106. def visit(self, tree):
  107. subtrees = list(tree.iter_subtrees())
  108. for subtree in reversed(subtrees):
  109. getattr(self, subtree.data, self.__default__)(subtree)
  110. return tree
  111. class Transformer_NoRecurse(Transformer):
  112. def transform(self, tree):
  113. subtrees = list(tree.iter_subtrees())
  114. def _t(t):
  115. # Assumes t is already transformed
  116. try:
  117. f = self._get_func(t.data)
  118. except AttributeError:
  119. return self.__default__(t)
  120. else:
  121. return f(t)
  122. for subtree in reversed(subtrees):
  123. subtree.children = [_t(c) if isinstance(c, Tree) else c for c in subtree.children]
  124. return _t(tree)
  125. def __default__(self, t):
  126. return t
  127. def pydot__tree_to_png(tree, filename):
  128. import pydot
  129. graph = pydot.Dot(graph_type='digraph', rankdir="LR")
  130. i = [0]
  131. def new_leaf(leaf):
  132. node = pydot.Node(i[0], label=repr(leaf))
  133. i[0] += 1
  134. graph.add_node(node)
  135. return node
  136. def _to_pydot(subtree):
  137. color = hash(subtree.data) & 0xffffff
  138. if not (color & 0x808080):
  139. color |= 0x808080
  140. subnodes = [_to_pydot(child) if isinstance(child, Tree) else new_leaf(child)
  141. for child in subtree.children]
  142. node = pydot.Node(i[0], style="filled", fillcolor="#%x"%color, label=subtree.data)
  143. i[0] += 1
  144. graph.add_node(node)
  145. for subnode in subnodes:
  146. graph.add_edge(pydot.Edge(node, subnode))
  147. return node
  148. _to_pydot(tree)
  149. graph.write_png(filename)