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.

217 lines
5.6 KiB

  1. from inspect import isclass, getmembers, getmro
  2. from functools import wraps
  3. from .utils import smart_decorator
  4. from .tree import Tree
  5. class Discard(Exception):
  6. pass
  7. # Transformers
  8. class Transformer:
  9. def _call_userfunc(self, data, children, meta):
  10. # Assumes tree is already transformed
  11. try:
  12. f = getattr(self, data)
  13. except AttributeError:
  14. return self.__default__(data, children, meta)
  15. else:
  16. if getattr(f, 'meta', False):
  17. return f(children, meta)
  18. elif getattr(f, 'inline', False):
  19. return f(*children)
  20. else:
  21. return f(children)
  22. def _transform_children(self, children):
  23. for c in children:
  24. try:
  25. yield self._transform_tree(c) if isinstance(c, Tree) else c
  26. except Discard:
  27. pass
  28. def _transform_tree(self, tree):
  29. children = list(self._transform_children(tree.children))
  30. return self._call_userfunc(tree.data, children, tree.meta)
  31. def transform(self, tree):
  32. return self._transform_tree(tree)
  33. def __mul__(self, other):
  34. return TransformerChain(self, other)
  35. def __default__(self, data, children, meta):
  36. "Default operation on tree (for override)"
  37. return Tree(data, children, meta)
  38. @classmethod
  39. def _apply_decorator(cls, decorator, **kwargs):
  40. mro = getmro(cls)
  41. assert mro[0] is cls
  42. libmembers = {name for _cls in mro[1:] for name, _ in getmembers(_cls)}
  43. for name, value in getmembers(cls):
  44. if name.startswith('_') or name in libmembers:
  45. continue
  46. setattr(cls, name, decorator(value, **kwargs))
  47. return cls
  48. class InlineTransformer(Transformer): # XXX Deprecated
  49. def _call_userfunc(self, data, children, meta):
  50. # Assumes tree is already transformed
  51. try:
  52. f = getattr(self, data)
  53. except AttributeError:
  54. return self.__default__(data, children, meta)
  55. else:
  56. return f(*children)
  57. class TransformerChain(object):
  58. def __init__(self, *transformers):
  59. self.transformers = transformers
  60. def transform(self, tree):
  61. for t in self.transformers:
  62. tree = t.transform(tree)
  63. return tree
  64. def __mul__(self, other):
  65. return TransformerChain(*self.transformers + (other,))
  66. class Transformer_InPlace(Transformer):
  67. def _transform_tree(self, tree): # Cancel recursion
  68. return self._call_userfunc(tree.data, tree.children, tree.meta)
  69. def transform(self, tree):
  70. for subtree in tree.iter_subtrees():
  71. subtree.children = list(self._transform_children(subtree.children))
  72. return self._transform_tree(tree)
  73. class Transformer_InPlaceRecursive(Transformer):
  74. def _transform_tree(self, tree):
  75. tree.children = list(self._transform_children(tree.children))
  76. return self._call_userfunc(tree.data, tree.children, tree.meta)
  77. # Visitors
  78. class VisitorBase:
  79. def _call_userfunc(self, tree):
  80. return getattr(self, tree.data, self.__default__)(tree)
  81. def __default__(self, tree):
  82. "Default operation on tree (for override)"
  83. return tree
  84. class Visitor(VisitorBase):
  85. "Bottom-up visitor"
  86. def visit(self, tree):
  87. for subtree in tree.iter_subtrees():
  88. self._call_userfunc(subtree)
  89. return tree
  90. class Visitor_Recursive(VisitorBase):
  91. def visit(self, tree):
  92. for child in tree.children:
  93. if isinstance(child, Tree):
  94. self.visit(child)
  95. f = getattr(self, tree.data, self.__default__)
  96. f(tree)
  97. return tree
  98. def visit_children_decor(func):
  99. @wraps(func)
  100. def inner(cls, tree):
  101. values = cls.visit_children(tree)
  102. return func(cls, values)
  103. return inner
  104. class Interpreter:
  105. "Top-down visitor"
  106. def visit(self, tree):
  107. return getattr(self, tree.data)(tree)
  108. def visit_children(self, tree):
  109. return [self.visit(child) if isinstance(child, Tree) else child
  110. for child in tree.children]
  111. def __getattr__(self, name):
  112. return self.__default__
  113. def __default__(self, tree):
  114. return self.visit_children(tree)
  115. # Decorators
  116. def _apply_decorator(obj, decorator, **kwargs):
  117. try:
  118. _apply = obj._apply_decorator
  119. except AttributeError:
  120. return decorator(obj, **kwargs)
  121. else:
  122. return _apply(decorator, **kwargs)
  123. def _inline_args__func(func):
  124. @wraps(func)
  125. def create_decorator(_f, with_self):
  126. if with_self:
  127. def f(self, children):
  128. return _f(self, *children)
  129. else:
  130. def f(self, children):
  131. return _f(*children)
  132. return f
  133. return smart_decorator(func, create_decorator)
  134. def inline_args(obj): # XXX Deprecated
  135. return _apply_decorator(obj, _inline_args__func)
  136. def _visitor_args_func_dec(func, inline=False, meta=False):
  137. assert not (inline and meta)
  138. def create_decorator(_f, with_self):
  139. if with_self:
  140. def f(self, *args, **kwargs):
  141. return _f(self, *args, **kwargs)
  142. else:
  143. def f(self, *args, **kwargs):
  144. return _f(*args, **kwargs)
  145. return f
  146. f = smart_decorator(func, create_decorator)
  147. f.inline = inline
  148. f.meta = meta
  149. return f
  150. def v_args(inline=False, meta=False):
  151. if inline and meta:
  152. raise ValueError("Visitor functions can either accept meta, or be inlined. Not both.")
  153. def _visitor_args_dec(obj):
  154. return _apply_decorator(obj, _visitor_args_func_dec, inline=inline, meta=meta)
  155. return _visitor_args_dec