This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

150 linhas
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