| @@ -1,6 +1,6 @@ | |||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
| from typing import Dict, Iterable, Callable, Union, TypeVar, Tuple | |||||
| from typing import Dict, Iterable, Callable, Union, TypeVar, Tuple, Any, List, Set | |||||
| from .tree import Tree | from .tree import Tree | ||||
| from .lexer import Token | from .lexer import Token | ||||
| @@ -25,7 +25,10 @@ T = TypeVar('T') | |||||
| class UnexpectedInput(LarkError): | class UnexpectedInput(LarkError): | ||||
| line: int | |||||
| column: int | |||||
| pos_in_stream: int | pos_in_stream: int | ||||
| state: Any | |||||
| def get_context(self, text: str, span: int = ...): | def get_context(self, text: str, span: int = ...): | ||||
| ... | ... | ||||
| @@ -41,12 +44,14 @@ class UnexpectedInput(LarkError): | |||||
| class UnexpectedToken(ParseError, UnexpectedInput): | class UnexpectedToken(ParseError, UnexpectedInput): | ||||
| pass | |||||
| expected: List[str] | |||||
| considered_rules: Set[str] | |||||
| puppet: Any | |||||
| accepts: List[str] | |||||
| class UnexpectedCharacters(LexError, UnexpectedInput): | class UnexpectedCharacters(LexError, UnexpectedInput): | ||||
| line: int | |||||
| column: int | |||||
| allowed: Set[str] | |||||
| considered_tokens: Set[Any] | |||||
| class VisitError(LarkError): | class VisitError(LarkError): | ||||
| @@ -105,7 +105,7 @@ class UnexpectedCharacters(LexError, UnexpectedInput): | |||||
| class UnexpectedToken(ParseError, UnexpectedInput): | class UnexpectedToken(ParseError, UnexpectedInput): | ||||
| def __init__(self, token, expected, considered_rules=None, state=None, puppet=None): | |||||
| def __init__(self, token, expected, considered_rules=None, state=None, puppet=None, accepts=None): | |||||
| self.token = token | self.token = token | ||||
| self.expected = expected # XXX str shouldn't necessary | self.expected = expected # XXX str shouldn't necessary | ||||
| self.line = getattr(token, 'line', '?') | self.line = getattr(token, 'line', '?') | ||||
| @@ -114,10 +114,11 @@ class UnexpectedToken(ParseError, UnexpectedInput): | |||||
| self.state = state | self.state = state | ||||
| self.pos_in_stream = getattr(token, 'pos_in_stream', None) | self.pos_in_stream = getattr(token, 'pos_in_stream', None) | ||||
| self.puppet = puppet | self.puppet = puppet | ||||
| self.accepts = accepts | |||||
| message = ("Unexpected token %r at line %s, column %s.\n" | message = ("Unexpected token %r at line %s, column %s.\n" | ||||
| "Expected one of: \n\t* %s\n" | "Expected one of: \n\t* %s\n" | ||||
| % (token, self.line, self.column, '\n\t* '.join(self.expected))) | |||||
| % (token, self.line, self.column, '\n\t* '.join(self.accepts or self.expected))) | |||||
| super(UnexpectedToken, self).__init__(message) | super(UnexpectedToken, self).__init__(message) | ||||
| @@ -62,9 +62,18 @@ class _Parser: | |||||
| expected = [s for s in states[state].keys() if s.isupper()] | expected = [s for s in states[state].keys() if s.isupper()] | ||||
| try: | try: | ||||
| puppet = ParserPuppet(self, state_stack, value_stack, start, stream, set_state) | puppet = ParserPuppet(self, state_stack, value_stack, start, stream, set_state) | ||||
| accepts = [] | |||||
| for t in expected: | |||||
| new_puppet = puppet.copy() | |||||
| try: | |||||
| new_puppet.feed_token(Token(t, '')) | |||||
| except KeyError: | |||||
| pass | |||||
| else: | |||||
| accepts.append(t) | |||||
| except NameError: | except NameError: | ||||
| puppet = None | |||||
| raise UnexpectedToken(token, expected, state=state, puppet=puppet) | |||||
| puppet = accepts = None | |||||
| raise UnexpectedToken(token, expected, state=state, puppet=puppet, accepts=accepts) | |||||
| def reduce(rule): | def reduce(rule): | ||||
| size = len(rule.expansion) | size = len(rule.expansion) | ||||