# This module provide a LALR puppet, which is used to debugging and error handling from copy import deepcopy from .lalr_analysis import Shift, Reduce from .. import Token class ParserPuppet(object): def __init__(self, parser, state_stack, value_stack, start, stream, set_state): self.parser = parser self._state_stack = state_stack self._value_stack = value_stack self._start = start self._stream = stream self._set_state = set_state self.result = None def feed_token(self, token): """Advance the parser state, as if it just received `token` from the lexer """ end_state = self.parser.parse_table.end_states[self._start] state_stack = self._state_stack value_stack = self._value_stack state = state_stack[-1] action, arg = self.parser.parse_table.states[state][token.type] assert arg != end_state while action is Reduce: rule = arg size = len(rule.expansion) if size: s = value_stack[-size:] del state_stack[-size:] del value_stack[-size:] else: s = [] value = self.parser.callbacks[rule](s) _action, new_state = self.parser.parse_table.states[state_stack[-1]][rule.origin.name] assert _action is Shift state_stack.append(new_state) value_stack.append(value) if state_stack[-1] == end_state: self.result = value_stack[-1] return self.result state = state_stack[-1] action, arg = self.parser.parse_table.states[state][token.type] assert arg != end_state assert action is Shift state_stack.append(arg) value_stack.append(token) def copy(self): return type(self)( self.parser, list(self._state_stack), deepcopy(self._value_stack), self._start, self._stream, self._set_state, ) def pretty(self): out = ["Puppet choices:"] for k, v in self.choices().items(): out.append('\t- %s -> %s' % (k, v)) out.append('stack size: %s' % len(self._state_stack)) return '\n'.join(out) def choices(self): return self.parser.parse_table.states[self._state_stack[-1]] def accepts(self): accepts = set() for t in self.choices(): new_puppet = self.copy() try: new_puppet.feed_token(Token(t, '')) except KeyError: pass else: accepts.add(t) return accepts def resume_parse(self): return self.parser.parse(self._stream, self._start, self._set_state, self._value_stack, self._state_stack)