This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

182 lignes
5.0 KiB

  1. try:
  2. from future_builtins import filter
  3. except ImportError:
  4. pass
  5. from copy import deepcopy
  6. ###{standalone
  7. class Meta:
  8. def __init__(self):
  9. self.empty = True
  10. class Tree(object):
  11. def __init__(self, data, children, meta=None):
  12. self.data = data
  13. self.children = children
  14. self._meta = meta
  15. @property
  16. def meta(self):
  17. if self._meta is None:
  18. self._meta = Meta()
  19. return self._meta
  20. def __repr__(self):
  21. return 'Tree(%s, %s)' % (self.data, self.children)
  22. def _pretty_label(self):
  23. return self.data
  24. def _pretty(self, level, indent_str):
  25. if len(self.children) == 1 and not isinstance(self.children[0], Tree):
  26. return [ indent_str*level, self._pretty_label(), '\t', '%s' % (self.children[0],), '\n']
  27. l = [ indent_str*level, self._pretty_label(), '\n' ]
  28. for n in self.children:
  29. if isinstance(n, Tree):
  30. l += n._pretty(level+1, indent_str)
  31. else:
  32. l += [ indent_str*(level+1), '%s' % (n,), '\n' ]
  33. return l
  34. def pretty(self, indent_str=' '):
  35. return ''.join(self._pretty(0, indent_str))
  36. def __eq__(self, other):
  37. try:
  38. return self.data == other.data and self.children == other.children
  39. except AttributeError:
  40. return False
  41. def __ne__(self, other):
  42. return not (self == other)
  43. def __hash__(self):
  44. return hash((self.data, tuple(self.children)))
  45. ###}
  46. def expand_kids_by_index(self, *indices):
  47. "Expand (inline) children at the given indices"
  48. for i in sorted(indices, reverse=True): # reverse so that changing tail won't affect indices
  49. kid = self.children[i]
  50. self.children[i:i+1] = kid.children
  51. def find_pred(self, pred):
  52. "Find all nodes where pred(tree) == True"
  53. return filter(pred, self.iter_subtrees())
  54. def find_data(self, data):
  55. "Find all nodes where tree.data == data"
  56. return self.find_pred(lambda t: t.data == data)
  57. def scan_values(self, pred):
  58. for c in self.children:
  59. if isinstance(c, Tree):
  60. for t in c.scan_values(pred):
  61. yield t
  62. else:
  63. if pred(c):
  64. yield c
  65. def iter_subtrees(self):
  66. # TODO: Re-write as a more efficient version
  67. visited = set()
  68. q = [self]
  69. l = []
  70. while q:
  71. subtree = q.pop()
  72. l.append( subtree )
  73. if id(subtree) in visited:
  74. continue # already been here from another branch
  75. visited.add(id(subtree))
  76. q += [c for c in subtree.children if isinstance(c, Tree)]
  77. seen = set()
  78. for x in reversed(l):
  79. if id(x) not in seen:
  80. yield x
  81. seen.add(id(x))
  82. def iter_subtrees_topdown(self):
  83. stack = [self]
  84. while stack:
  85. node = stack.pop()
  86. if not isinstance(node, Tree):
  87. continue
  88. yield node
  89. for n in reversed(node.children):
  90. stack.append(n)
  91. def __deepcopy__(self, memo):
  92. return type(self)(self.data, deepcopy(self.children, memo))
  93. def copy(self):
  94. return type(self)(self.data, self.children)
  95. def set(self, data, children):
  96. self.data = data
  97. self.children = children
  98. # XXX Deprecated! Here for backwards compatibility <0.6.0
  99. @property
  100. def line(self):
  101. return self.meta.line
  102. @property
  103. def column(self):
  104. return self.meta.column
  105. @property
  106. def end_line(self):
  107. return self.meta.end_line
  108. @property
  109. def end_column(self):
  110. return self.meta.end_column
  111. class SlottedTree(Tree):
  112. __slots__ = 'data', 'children', 'rule', '_meta'
  113. def pydot__tree_to_png(tree, filename, rankdir="LR"):
  114. """Creates a colorful image that represents the tree (data+children, without meta)
  115. Possible values for `rankdir` are "TB", "LR", "BT", "RL", corresponding to
  116. directed graphs drawn from top to bottom, from left to right, from bottom to
  117. top, and from right to left, respectively. See:
  118. https://www.graphviz.org/doc/info/attrs.html#k:rankdir
  119. """
  120. import pydot
  121. graph = pydot.Dot(graph_type='digraph', rankdir=rankdir)
  122. i = [0]
  123. def new_leaf(leaf):
  124. node = pydot.Node(i[0], label=repr(leaf))
  125. i[0] += 1
  126. graph.add_node(node)
  127. return node
  128. def _to_pydot(subtree):
  129. color = hash(subtree.data) & 0xffffff
  130. color |= 0x808080
  131. subnodes = [_to_pydot(child) if isinstance(child, Tree) else new_leaf(child)
  132. for child in subtree.children]
  133. node = pydot.Node(i[0], style="filled", fillcolor="#%x"%color, label=subtree.data)
  134. i[0] += 1
  135. graph.add_node(node)
  136. for subnode in subnodes:
  137. graph.add_edge(pydot.Edge(node, subnode))
  138. return node
  139. _to_pydot(tree)
  140. graph.write_png(filename)