This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

129 行
4.4 KiB

  1. from .common import is_terminal, GrammarError
  2. from .utils import suppress
  3. from .lexer import Token
  4. class Callback(object):
  5. pass
  6. def create_expand1_tree_builder_function(tree_builder):
  7. def expand1(children):
  8. if len(children) == 1:
  9. return children[0]
  10. else:
  11. return tree_builder(children)
  12. return expand1
  13. def create_token_wrapper(tree_builder, name):
  14. def join_children(children):
  15. children = [Token(name, ''.join(children))]
  16. return tree_builder(children)
  17. return join_children
  18. def create_rule_handler(expansion, usermethod, keep_all_tokens, filter_out):
  19. # if not keep_all_tokens:
  20. to_include = [(i, not is_terminal(sym) and sym.startswith('_'))
  21. for i, sym in enumerate(expansion)
  22. if keep_all_tokens
  23. or not ((is_terminal(sym) and sym.startswith('_')) or sym in filter_out)
  24. ]
  25. if len(to_include) < len(expansion) or any(to_expand for i, to_expand in to_include):
  26. def _build_ast(match):
  27. children = []
  28. for i, to_expand in to_include:
  29. if to_expand:
  30. children += match[i].children
  31. else:
  32. children.append(match[i])
  33. return usermethod(children)
  34. return _build_ast
  35. # else, if no filtering required..
  36. return usermethod
  37. def propagate_positions_wrapper(f):
  38. def _f(args):
  39. res = f(args)
  40. if args:
  41. for a in args:
  42. with suppress(AttributeError):
  43. res.line = a.line
  44. res.column = a.column
  45. break
  46. for a in reversed(args):
  47. with suppress(AttributeError):
  48. res.end_line = a.end_line
  49. res.end_col = a.end_col
  50. break
  51. return res
  52. return _f
  53. class ParseTreeBuilder:
  54. def __init__(self, tree_class, propagate_positions=False, keep_all_tokens=False):
  55. self.tree_class = tree_class
  56. self.propagate_positions = propagate_positions
  57. self.always_keep_all_tokens = keep_all_tokens
  58. def _create_tree_builder_function(self, name):
  59. tree_class = self.tree_class
  60. def tree_builder_f(children):
  61. return tree_class(name, children)
  62. return tree_builder_f
  63. def create_tree_builder(self, rules, transformer):
  64. callback = Callback()
  65. new_rules = []
  66. filter_out = set()
  67. for origin, (expansions, options) in rules.items():
  68. if options and options.filter_out:
  69. assert origin.startswith('_') # Just to make sure
  70. filter_out.add(origin)
  71. for origin, (expansions, options) in rules.items():
  72. keep_all_tokens = self.always_keep_all_tokens or (options.keep_all_tokens if options else False)
  73. expand1 = options.expand1 if options else False
  74. create_token = options.create_token if options else False
  75. _origin = origin
  76. for expansion, alias in expansions:
  77. if alias and origin.startswith('_'):
  78. raise Exception("Rule %s is marked for expansion (it starts with an underscore) and isn't allowed to have aliases (alias=%s)" % (origin, alias))
  79. try:
  80. f = transformer._get_func(alias or _origin)
  81. except AttributeError:
  82. if alias:
  83. f = self._create_tree_builder_function(alias)
  84. else:
  85. f = self._create_tree_builder_function(_origin)
  86. if expand1:
  87. f = create_expand1_tree_builder_function(f)
  88. if create_token:
  89. f = create_token_wrapper(f, create_token)
  90. alias_handler = create_rule_handler(expansion, f, keep_all_tokens, filter_out)
  91. if self.propagate_positions:
  92. alias_handler = propagate_positions_wrapper(alias_handler)
  93. callback_name = 'autoalias_%s_%s' % (_origin, '_'.join(expansion))
  94. if hasattr(callback, callback_name):
  95. raise GrammarError("Rule expansion '%s' already exists in rule %s" % (' '.join(expansion), origin))
  96. setattr(callback, callback_name, alias_handler)
  97. new_rules.append(( _origin, expansion, callback_name, options ))
  98. return new_rules, callback