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.

150 rivejä
4.0 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(self, level, indent_str):
  10. if len(self.children) == 1 and not isinstance(self.children[0], Tree):
  11. return [ indent_str*level, self.data, '\t', '%s' % self.children[0], '\n']
  12. l = [ indent_str*level, self.data, '\n' ]
  13. for n in self.children:
  14. if isinstance(n, Tree):
  15. l += n._pretty(level+1, indent_str)
  16. else:
  17. l += [ indent_str*(level+1), '%s' % n, '\n' ]
  18. return l
  19. def pretty(self, indent_str=' '):
  20. return ''.join(self._pretty(0, indent_str))
  21. def expand_kids_by_index(self, *indices):
  22. for i in sorted(indices, reverse=True): # reverse so that changing tail won't affect indices
  23. kid = self.children[i]
  24. self.children[i:i+1] = kid.children
  25. def __eq__(self, other):
  26. try:
  27. return self.data == other.data and self.children == other.children
  28. except AttributeError:
  29. return False
  30. def __hash__(self):
  31. return hash((self.data, tuple(self.children)))
  32. def find_pred(self, pred):
  33. if pred(self):
  34. yield self
  35. for c in self.children:
  36. if isinstance(c, Tree):
  37. for t in c.find_pred(pred):
  38. yield t
  39. def find_data(self, data):
  40. return self.find_pred(lambda t: t.data == data)
  41. def scan_values(self, pred):
  42. for c in self.children:
  43. if isinstance(c, Tree):
  44. for t in c.scan_values(pred):
  45. yield t
  46. else:
  47. if pred(c):
  48. yield c
  49. def iter_subtrees(self):
  50. q = [self]
  51. while q:
  52. subtree = q.pop()
  53. yield subtree
  54. q += [c for c in subtree.children if isinstance(c, Tree)]
  55. def __deepcopy__(self, memo):
  56. return type(self)(self.data, deepcopy(self.children, memo))
  57. def copy(self):
  58. return type(self)(self.data, self.children)
  59. def set(self, data, children):
  60. self.data = data
  61. self.children = children
  62. class Transformer(object):
  63. def _get_func(self, name):
  64. return getattr(self, name)
  65. def transform(self, tree):
  66. items = [self.transform(c) if isinstance(c, Tree) else c for c in tree.children]
  67. try:
  68. f = self._get_func(tree.data)
  69. except AttributeError:
  70. return self.__default__(tree.data, items)
  71. else:
  72. return f(items)
  73. def __default__(self, data, children):
  74. return Tree(data, children)
  75. class InlineTransformer(Transformer):
  76. def _get_func(self, name): # use super()._get_func
  77. return inline_args(getattr(self, name)).__get__(self)
  78. class Visitor(object):
  79. def visit(self, tree):
  80. for child in tree.children:
  81. if isinstance(child, Tree):
  82. self.visit(child)
  83. f = getattr(self, tree.data, self.__default__)
  84. f(tree)
  85. return tree
  86. def __default__(self, tree):
  87. pass
  88. class Visitor_NoRecurse(Visitor):
  89. def visit(self, tree):
  90. subtrees = list(tree.iter_subtrees())
  91. for subtree in reversed(subtrees):
  92. getattr(self, subtree.data, self.__default__)(subtree)
  93. return tree
  94. class Transformer_NoRecurse(Transformer):
  95. def transform(self, tree):
  96. subtrees = list(tree.iter_subtrees())
  97. def _t(t):
  98. # Assumes t is already transformed
  99. try:
  100. f = self._get_func(t.data)
  101. except AttributeError:
  102. return self.__default__(t)
  103. else:
  104. return f(t)
  105. for subtree in reversed(subtrees):
  106. subtree.children = [_t(c) if isinstance(c, Tree) else c for c in subtree.children]
  107. return _t(tree)
  108. def __default__(self, t):
  109. return t