Newton_Editor/plugins/snippets/cson/speg/errors.py

67 lines
2.1 KiB
Python

from .rules import rule_to_str
class ExpectedExpr:
def __init__(self, expr, callstack):
self.expr = expr
self.callstack = callstack
class UnexpectedExpr:
def __init__(self, end_pos, rule, callstack):
self.end_pos = end_pos
self.rule = rule
self.callstack = callstack
class SemanticFailure:
def __init__(self, args, kw, callstack):
self.args = args
self.kw = kw
self.callstack = callstack
class ParseError(RuntimeError):
def __init__(self, message, text, start_pos, end_pos, failures):
self.message = message
self.text = text
self.start_pos = start_pos
self.end_pos = end_pos
self.failures = failures
def __str__(self):
return 'at {}:{}: {}'.format(
self.start_pos.line, self.start_pos.col, self.message)
def _first(iterable):
return next(iterable, None)
def raise_parsing_error(text, position, failures):
end_pos = position
msg = []
sema = _first(f for f in failures if isinstance(f, SemanticFailure))
if sema is not None:
msg.append(sema.args[0])
else:
unexps = [f for f in failures if isinstance(f, UnexpectedExpr)]
if unexps:
unexp = min(unexps,
key=lambda f: f.end_pos.offset - position.offset)
end_pos = unexp.end_pos
msg.append('unexpected {}'.format(rule_to_str(unexp.rule)))
exps = [f for f in failures if isinstance(f, ExpectedExpr)]
if exps:
exp_syms = set()
for f in exps:
r = _first(se.fn for se in f.callstack
if se.position == position and not getattr(se.fn, '_speg_hidden', False))
if r is None:
r = f.expr
exp_syms.add(rule_to_str(r))
exp_strs = sorted(exp_syms)
if len(exp_strs) == 1:
msg.append('expected {}'.format(exp_strs[0]))
else:
msg.append('expected one of {}'.format(', '.join(exp_strs)))
raise ParseError('; '.join(msg), text, position, end_pos, failures)