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.

260 lines
6.6 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. ###{standalone
  8. class Tree(object):
  9. def __init__(self, data, children):
  10. self.data = data
  11. self.children = children
  12. def __repr__(self):
  13. return 'Tree(%s, %s)' % (self.data, self.children)
  14. def _pretty_label(self):
  15. return self.data
  16. def _pretty(self, level, indent_str):
  17. if len(self.children) == 1 and not isinstance(self.children[0], Tree):
  18. return [ indent_str*level, self._pretty_label(), '\t', '%s' % (self.children[0],), '\n']
  19. l = [ indent_str*level, self._pretty_label(), '\n' ]
  20. for n in self.children:
  21. if isinstance(n, Tree):
  22. l += n._pretty(level+1, indent_str)
  23. else:
  24. l += [ indent_str*(level+1), '%s' % (n,), '\n' ]
  25. return l
  26. def pretty(self, indent_str=' '):
  27. return ''.join(self._pretty(0, indent_str))
  28. ###}
  29. def expand_kids_by_index(self, *indices):
  30. for i in sorted(indices, reverse=True): # reverse so that changing tail won't affect indices
  31. kid = self.children[i]
  32. self.children[i:i+1] = kid.children
  33. def __eq__(self, other):
  34. try:
  35. return self.data == other.data and self.children == other.children
  36. except AttributeError:
  37. return False
  38. def __ne__(self, other):
  39. return not (self == other)
  40. def __hash__(self):
  41. return hash((self.data, tuple(self.children)))
  42. def find_pred(self, pred):
  43. return filter(pred, self.iter_subtrees())
  44. def find_data(self, data):
  45. return self.find_pred(lambda t: t.data == data)
  46. def scan_values(self, pred):
  47. for c in self.children:
  48. if isinstance(c, Tree):
  49. for t in c.scan_values(pred):
  50. yield t
  51. else:
  52. if pred(c):
  53. yield c
  54. def iter_subtrees(self):
  55. # TODO: Re-write as a more efficient version
  56. visited = set()
  57. q = [self]
  58. l = []
  59. while q:
  60. subtree = q.pop()
  61. l.append( subtree )
  62. if id(subtree) in visited:
  63. continue # already been here from another branch
  64. visited.add(id(subtree))
  65. q += [c for c in subtree.children if isinstance(c, Tree)]
  66. seen = set()
  67. for x in reversed(l):
  68. if id(x) not in seen:
  69. yield x
  70. seen.add(id(x))
  71. def __deepcopy__(self, memo):
  72. return type(self)(self.data, deepcopy(self.children, memo))
  73. def copy(self):
  74. return type(self)(self.data, self.children)
  75. def set(self, data, children):
  76. self.data = data
  77. self.children = children
  78. class SlottedTree(Tree):
  79. __slots__ = 'data', 'children', 'rule'
  80. ###{standalone
  81. class Transformer(object):
  82. def _get_func(self, name):
  83. return getattr(self, name)
  84. def transform(self, tree):
  85. items = []
  86. for c in tree.children:
  87. try:
  88. items.append(self.transform(c) if isinstance(c, Tree) else c)
  89. except Discard:
  90. pass
  91. try:
  92. f = self._get_func(tree.data)
  93. except AttributeError:
  94. return self.__default__(tree.data, items)
  95. else:
  96. return f(items)
  97. def __default__(self, data, children):
  98. return Tree(data, children)
  99. def __mul__(self, other):
  100. return TransformerChain(self, other)
  101. class Discard(Exception):
  102. pass
  103. class TransformerChain(object):
  104. def __init__(self, *transformers):
  105. self.transformers = transformers
  106. def transform(self, tree):
  107. for t in self.transformers:
  108. tree = t.transform(tree)
  109. return tree
  110. def __mul__(self, other):
  111. return TransformerChain(*self.transformers + (other,))
  112. class InlineTransformer(Transformer):
  113. def _get_func(self, name): # use super()._get_func
  114. return inline_args(getattr(self, name)).__get__(self)
  115. class Visitor(object):
  116. def visit(self, tree):
  117. for child in tree.children:
  118. if isinstance(child, Tree):
  119. self.visit(child)
  120. f = getattr(self, tree.data, self.__default__)
  121. f(tree)
  122. return tree
  123. def __default__(self, tree):
  124. pass
  125. class Visitor_NoRecurse(Visitor):
  126. def visit(self, tree):
  127. subtrees = list(tree.iter_subtrees())
  128. for subtree in (subtrees):
  129. getattr(self, subtree.data, self.__default__)(subtree)
  130. return tree
  131. from functools import wraps
  132. def visit_children_decor(func):
  133. @wraps(func)
  134. def inner(cls, tree):
  135. values = cls.visit_children(tree)
  136. return func(cls, values)
  137. return inner
  138. class Interpreter(object):
  139. def visit(self, tree):
  140. return getattr(self, tree.data)(tree)
  141. def visit_children(self, tree):
  142. return [self.visit(child) if isinstance(child, Tree) else child
  143. for child in tree.children]
  144. def __getattr__(self, name):
  145. return self.__default__
  146. def __default__(self, tree):
  147. return self.visit_children(tree)
  148. class Transformer_NoRecurse(Transformer):
  149. def transform(self, tree):
  150. subtrees = list(tree.iter_subtrees())
  151. def _t(t):
  152. # Assumes t is already transformed
  153. try:
  154. f = self._get_func(t.data)
  155. except AttributeError:
  156. return self.__default__(t)
  157. else:
  158. return f(t)
  159. for subtree in subtrees:
  160. children = []
  161. for c in subtree.children:
  162. try:
  163. children.append(_t(c) if isinstance(c, Tree) else c)
  164. except Discard:
  165. pass
  166. subtree.children = children
  167. return _t(tree)
  168. def __default__(self, t):
  169. return t
  170. ###}
  171. def pydot__tree_to_png(tree, filename):
  172. import pydot
  173. graph = pydot.Dot(graph_type='digraph', rankdir="LR")
  174. i = [0]
  175. def new_leaf(leaf):
  176. node = pydot.Node(i[0], label=repr(leaf))
  177. i[0] += 1
  178. graph.add_node(node)
  179. return node
  180. def _to_pydot(subtree):
  181. color = hash(subtree.data) & 0xffffff
  182. color |= 0x808080
  183. subnodes = [_to_pydot(child) if isinstance(child, Tree) else new_leaf(child)
  184. for child in subtree.children]
  185. node = pydot.Node(i[0], style="filled", fillcolor="#%x"%color, label=subtree.data)
  186. i[0] += 1
  187. graph.add_node(node)
  188. for subnode in subnodes:
  189. graph.add_edge(pydot.Edge(node, subnode))
  190. return node
  191. _to_pydot(tree)
  192. graph.write_png(filename)