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.

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