Просмотр исходного кода

Added considered_rules to exception for earley. Small improvement to docs and exceptions

tags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.11.3
Erez Sh 3 лет назад
Родитель
Сommit
0a380b7c2a
3 измененных файлов: 34 добавлений и 3 удалений
  1. +27
    -0
      docs/recipes.md
  2. +3
    -2
      lark/exceptions.py
  3. +4
    -1
      lark/parsers/xearley.py

+ 27
- 0
docs/recipes.md Просмотреть файл

@@ -145,3 +145,30 @@ class Parent(Visitor):
assert not hasattr(subtree, 'parent')
subtree.parent = tree
```


## Unwinding VisitError after a transformer/visitor exception

Errors that happen inside visitors and transformers get wrapped inside a `VisitError` exception.

This can often be inconvenient, if you wish the actual error to propagate upwards, or if you want to catch it.

But, it's easy to unwrap it at the point of calling the transformer, by catching it and raising the `VisitError.orig_exc` attribute.

For example:
```python
from lark import Lark, Transformer
from lark.visitors import VisitError

tree = Lark('start: "a"').parse('a')

class T(Transformer):
def start(self, x):
raise KeyError("Original Exception")

t = T()
try:
print( t.transform(tree))
except VisitError as e:
raise e.orig_exc
```

+ 3
- 2
lark/exceptions.py Просмотреть файл

@@ -148,7 +148,7 @@ class UnexpectedEOF(ParseError, UnexpectedInput):

class UnexpectedCharacters(LexError, UnexpectedInput):
def __init__(self, seq, lex_pos, line, column, allowed=None, considered_tokens=None, state=None, token_history=None,
terminals_by_name=None):
terminals_by_name=None, considered_rules=None):
# TODO considered_tokens and allowed can be figured out using state
self.line = line
self.column = column
@@ -158,6 +158,7 @@ class UnexpectedCharacters(LexError, UnexpectedInput):

self.allowed = allowed
self.considered_tokens = considered_tokens
self.considered_rules = considered_rules
self.token_history = token_history

if isinstance(seq, bytes):
@@ -169,7 +170,7 @@ class UnexpectedCharacters(LexError, UnexpectedInput):
super(UnexpectedCharacters, self).__init__()

def __str__(self):
message = "No terminal defined for '%s' at line %d col %d" % (self.char, self.line, self.column)
message = "No terminal matches '%s' in the current parser context, at line %d col %d" % (self.char, self.line, self.column)
message += '\n\n' + self._context
if self.allowed:
message += self._format_expected(self.allowed)


+ 4
- 1
lark/parsers/xearley.py Просмотреть файл

@@ -114,8 +114,11 @@ class Parser(BaseParser):
del delayed_matches[i+1] # No longer needed, so unburden memory

if not next_set and not delayed_matches and not next_to_scan:
considered_rules = list(sorted(to_scan, key=lambda key: key.rule.origin.name))
raise UnexpectedCharacters(stream, i, text_line, text_column, {item.expect.name for item in to_scan},
set(to_scan), state=frozenset(i.s for i in to_scan))
set(to_scan), state=frozenset(i.s for i in to_scan),
considered_rules=considered_rules
)

return next_to_scan



Загрузка…
Отмена
Сохранить