This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
5.5 KiB

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