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

103 行
3.6 KiB

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