This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.8 KiB

  1. from .utils import STRING_TYPE
  2. class LarkError(Exception):
  3. pass
  4. class GrammarError(LarkError):
  5. pass
  6. class ParseError(LarkError):
  7. pass
  8. class LexError(LarkError):
  9. pass
  10. class UnexpectedInput(LarkError):
  11. pos_in_stream = None
  12. def get_context(self, text, span=40):
  13. pos = self.pos_in_stream
  14. start = max(pos - span, 0)
  15. end = pos + span
  16. before = text[start:pos].rsplit('\n', 1)[-1]
  17. after = text[pos:end].split('\n', 1)[0]
  18. return before + after + '\n' + ' ' * len(before) + '^\n'
  19. def match_examples(self, parse_fn, examples):
  20. """ Given a parser instance and a dictionary mapping some label with
  21. some malformed syntax examples, it'll return the label for the
  22. example that bests matches the current error.
  23. """
  24. assert self.state is not None, "Not supported for this exception"
  25. candidate = None
  26. for label, example in examples.items():
  27. assert not isinstance(example, STRING_TYPE)
  28. for malformed in example:
  29. try:
  30. parse_fn(malformed)
  31. except UnexpectedInput as ut:
  32. if ut.state == self.state:
  33. try:
  34. if ut.token == self.token: # Try exact match first
  35. return label
  36. except AttributeError:
  37. pass
  38. if not candidate:
  39. candidate = label
  40. return candidate
  41. class UnexpectedCharacters(LexError, UnexpectedInput):
  42. def __init__(self, seq, lex_pos, line, column, allowed=None, considered_tokens=None, state=None):
  43. message = "No terminal defined for '%s' at line %d col %d" % (seq[lex_pos], line, column)
  44. self.line = line
  45. self.column = column
  46. self.allowed = allowed
  47. self.considered_tokens = considered_tokens
  48. self.pos_in_stream = lex_pos
  49. self.state = state
  50. message += '\n\n' + self.get_context(seq)
  51. if allowed:
  52. message += '\nExpecting: %s\n' % allowed
  53. super(UnexpectedCharacters, self).__init__(message)
  54. class UnexpectedToken(ParseError, UnexpectedInput):
  55. def __init__(self, token, expected, considered_rules=None, state=None):
  56. self.token = token
  57. self.expected = expected # XXX str shouldn't necessary
  58. self.line = getattr(token, 'line', '?')
  59. self.column = getattr(token, 'column', '?')
  60. self.considered_rules = considered_rules
  61. self.state = state
  62. self.pos_in_stream = getattr(token, 'pos_in_stream', None)
  63. message = ("Unexpected token %r at line %s, column %s.\n"
  64. "Expected: %s\n"
  65. % (token, self.line, self.column, ', '.join(self.expected)))
  66. super(UnexpectedToken, self).__init__(message)