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.

95 lines
2.8 KiB

  1. # This module provide a LALR puppet, which is used to debugging and error handling
  2. from copy import deepcopy
  3. from .lalr_analysis import Shift, Reduce
  4. from .. import Token
  5. class ParserPuppet(object):
  6. def __init__(self, parser, state_stack, value_stack, start, stream, set_state):
  7. self.parser = parser
  8. self._state_stack = state_stack
  9. self._value_stack = value_stack
  10. self._start = start
  11. self._stream = stream
  12. self._set_state = set_state
  13. self.result = None
  14. def feed_token(self, token):
  15. """Advance the parser state, as if it just received `token` from the lexer
  16. """
  17. end_state = self.parser.parse_table.end_states[self._start]
  18. state_stack = self._state_stack
  19. value_stack = self._value_stack
  20. state = state_stack[-1]
  21. action, arg = self.parser.parse_table.states[state][token.type]
  22. assert arg != end_state
  23. while action is Reduce:
  24. rule = arg
  25. size = len(rule.expansion)
  26. if size:
  27. s = value_stack[-size:]
  28. del state_stack[-size:]
  29. del value_stack[-size:]
  30. else:
  31. s = []
  32. value = self.parser.callbacks[rule](s)
  33. _action, new_state = self.parser.parse_table.states[state_stack[-1]][rule.origin.name]
  34. assert _action is Shift
  35. state_stack.append(new_state)
  36. value_stack.append(value)
  37. if state_stack[-1] == end_state:
  38. self.result = value_stack[-1]
  39. return self.result
  40. state = state_stack[-1]
  41. action, arg = self.parser.parse_table.states[state][token.type]
  42. assert arg != end_state
  43. assert action is Shift
  44. state_stack.append(arg)
  45. value_stack.append(token)
  46. def copy(self):
  47. return type(self)(
  48. self.parser,
  49. list(self._state_stack),
  50. deepcopy(self._value_stack),
  51. self._start,
  52. self._stream,
  53. self._set_state,
  54. )
  55. def pretty(self):
  56. out = ["Puppet choices:"]
  57. for k, v in self.choices().items():
  58. out.append('\t- %s -> %s' % (k, v))
  59. out.append('stack size: %s' % len(self._state_stack))
  60. return '\n'.join(out)
  61. def choices(self):
  62. return self.parser.parse_table.states[self._state_stack[-1]]
  63. def accepts(self):
  64. accepts = set()
  65. for t in self.choices():
  66. new_puppet = self.copy()
  67. try:
  68. new_puppet.feed_token(Token(t, ''))
  69. except KeyError:
  70. pass
  71. else:
  72. accepts.add(t)
  73. return accepts
  74. def resume_parse(self):
  75. return self.parser.parse(self._stream, self._start, self._set_state, self._value_stack, self._state_stack)