This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

142 Zeilen
4.5 KiB

  1. from .common import is_terminal, GrammarError
  2. from .utils import suppress
  3. from .lexer import Token
  4. from .grammar import Rule
  5. ###{standalone
  6. from functools import partial
  7. class ExpandSingleChild:
  8. def __init__(self, node_builder):
  9. self.node_builder = node_builder
  10. def __call__(self, children):
  11. if len(children) == 1:
  12. return children[0]
  13. else:
  14. return self.node_builder(children)
  15. class CreateToken:
  16. "Used for fixing the results of scanless parsing"
  17. def __init__(self, token_name, node_builder):
  18. self.node_builder = node_builder
  19. self.token_name = token_name
  20. def __call__(self, children):
  21. return self.node_builder( [Token(self.token_name, ''.join(children))] )
  22. class PropagatePositions:
  23. def __init__(self, node_builder):
  24. self.node_builder = node_builder
  25. def __call__(self, children):
  26. res = self.node_builder(children)
  27. if children:
  28. for a in children:
  29. with suppress(AttributeError):
  30. res.line = a.line
  31. res.column = a.column
  32. break
  33. for a in reversed(children):
  34. with suppress(AttributeError):
  35. res.end_line = a.end_line
  36. res.end_column = a.end_column
  37. break
  38. return res
  39. class ChildFilter:
  40. def __init__(self, to_include, node_builder):
  41. self.node_builder = node_builder
  42. self.to_include = to_include
  43. def __call__(self, children):
  44. filtered = []
  45. for i, to_expand in self.to_include:
  46. if to_expand:
  47. if filtered:
  48. filtered += children[i].children
  49. else: # Optimize for left-recursion
  50. filtered = children[i].children
  51. else:
  52. filtered.append(children[i])
  53. return self.node_builder(filtered)
  54. def _should_expand(sym):
  55. return not is_terminal(sym) and sym.startswith('_')
  56. def maybe_create_child_filter(expansion, filter_out):
  57. to_include = [(i, _should_expand(sym)) for i, sym in enumerate(expansion) if sym not in filter_out]
  58. if len(to_include) < len(expansion) or any(to_expand for i, to_expand in to_include):
  59. return partial(ChildFilter, to_include)
  60. class Callback(object):
  61. pass
  62. class ParseTreeBuilder:
  63. def __init__(self, rules, tree_class, propagate_positions=False, keep_all_tokens=False):
  64. self.tree_class = tree_class
  65. self.propagate_positions = propagate_positions
  66. self.always_keep_all_tokens = keep_all_tokens
  67. self.rule_builders = list(self._init_builders(rules))
  68. self.user_aliases = {}
  69. def _init_builders(self, rules):
  70. filter_out = {rule.origin for rule in rules if rule.options and rule.options.filter_out}
  71. filter_out |= {sym for rule in rules for sym in rule.expansion if is_terminal(sym) and sym.startswith('_')}
  72. assert all(x.startswith('_') for x in filter_out)
  73. for rule in rules:
  74. options = rule.options
  75. keep_all_tokens = self.always_keep_all_tokens or (options.keep_all_tokens if options else False)
  76. expand_single_child = options.expand1 if options else False
  77. create_token = options.create_token if options else False
  78. wrapper_chain = filter(None, [
  79. create_token and partial(CreateToken, create_token),
  80. (expand_single_child and not rule.alias) and ExpandSingleChild,
  81. maybe_create_child_filter(rule.expansion, () if keep_all_tokens else filter_out),
  82. self.propagate_positions and PropagatePositions,
  83. ])
  84. yield rule, wrapper_chain
  85. def create_callback(self, transformer=None):
  86. callback = Callback()
  87. for rule, wrapper_chain in self.rule_builders:
  88. internal_callback_name = '_callback_%s_%s' % (rule.origin, '_'.join(rule.expansion))
  89. user_callback_name = rule.alias or rule.origin
  90. try:
  91. f = transformer._get_func(user_callback_name)
  92. except AttributeError:
  93. f = partial(self.tree_class, user_callback_name)
  94. self.user_aliases[rule] = rule.alias
  95. rule.alias = internal_callback_name
  96. for w in wrapper_chain:
  97. f = w(f)
  98. if hasattr(callback, internal_callback_name):
  99. raise GrammarError("Rule '%s' already exists" % (rule,))
  100. setattr(callback, internal_callback_name, f)
  101. return callback
  102. ###}