diff --git a/lark-stubs/exceptions.pyi b/lark-stubs/exceptions.pyi index 012ac51..67c39fb 100644 --- a/lark-stubs/exceptions.pyi +++ b/lark-stubs/exceptions.pyi @@ -1,6 +1,6 @@ # -*- 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 .lexer import Token @@ -25,7 +25,10 @@ T = TypeVar('T') class UnexpectedInput(LarkError): + line: int + column: int pos_in_stream: int + state: Any def get_context(self, text: str, span: int = ...): ... @@ -41,12 +44,14 @@ class UnexpectedInput(LarkError): class UnexpectedToken(ParseError, UnexpectedInput): - pass - + expected: List[str] + considered_rules: Set[str] + puppet: Any + accepts: List[str] class UnexpectedCharacters(LexError, UnexpectedInput): - line: int - column: int + allowed: Set[str] + considered_tokens: Set[Any] class VisitError(LarkError): diff --git a/lark/exceptions.py b/lark/exceptions.py index 47670a6..022a00f 100644 --- a/lark/exceptions.py +++ b/lark/exceptions.py @@ -105,7 +105,7 @@ class UnexpectedCharacters(LexError, 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.expected = expected # XXX str shouldn't necessary self.line = getattr(token, 'line', '?') @@ -114,10 +114,11 @@ class UnexpectedToken(ParseError, UnexpectedInput): self.state = state self.pos_in_stream = getattr(token, 'pos_in_stream', None) self.puppet = puppet + self.accepts = accepts message = ("Unexpected token %r at line %s, column %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) diff --git a/lark/parsers/lalr_parser.py b/lark/parsers/lalr_parser.py index f26cbc5..f61e093 100644 --- a/lark/parsers/lalr_parser.py +++ b/lark/parsers/lalr_parser.py @@ -62,9 +62,18 @@ class _Parser: expected = [s for s in states[state].keys() if s.isupper()] try: 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: - 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): size = len(rule.expansion)