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.

113 lines
3.8 KiB

  1. from .utils import STRING_TYPE
  2. ###{standalone
  3. class LarkError(Exception):
  4. pass
  5. class GrammarError(LarkError):
  6. pass
  7. class ParseError(LarkError):
  8. pass
  9. class LexError(LarkError):
  10. pass
  11. class UnexpectedEOF(ParseError):
  12. def __init__(self, expected):
  13. self.expected = expected
  14. message = ("Unexpected end-of-input. Expected one of: \n\t* %s\n" % '\n\t* '.join(x.name for x in self.expected))
  15. super(UnexpectedEOF, self).__init__(message)
  16. class UnexpectedInput(LarkError):
  17. pos_in_stream = None
  18. def get_context(self, text, span=40):
  19. pos = self.pos_in_stream
  20. start = max(pos - span, 0)
  21. end = pos + span
  22. before = text[start:pos].rsplit('\n', 1)[-1]
  23. after = text[pos:end].split('\n', 1)[0]
  24. return before + after + '\n' + ' ' * len(before) + '^\n'
  25. def match_examples(self, parse_fn, examples):
  26. """ Given a parser instance and a dictionary mapping some label with
  27. some malformed syntax examples, it'll return the label for the
  28. example that bests matches the current error.
  29. """
  30. assert self.state is not None, "Not supported for this exception"
  31. candidate = None
  32. for label, example in examples.items():
  33. assert not isinstance(example, STRING_TYPE)
  34. for malformed in example:
  35. try:
  36. parse_fn(malformed)
  37. except UnexpectedInput as ut:
  38. if ut.state == self.state:
  39. try:
  40. if ut.token == self.token: # Try exact match first
  41. return label
  42. except AttributeError:
  43. pass
  44. if not candidate:
  45. candidate = label
  46. return candidate
  47. class UnexpectedCharacters(LexError, UnexpectedInput):
  48. def __init__(self, seq, lex_pos, line, column, allowed=None, considered_tokens=None, state=None, token_history=None):
  49. message = "No terminal defined for '%s' at line %d col %d" % (seq[lex_pos], line, column)
  50. self.line = line
  51. self.column = column
  52. self.allowed = allowed
  53. self.considered_tokens = considered_tokens
  54. self.pos_in_stream = lex_pos
  55. self.state = state
  56. message += '\n\n' + self.get_context(seq)
  57. if allowed:
  58. message += '\nExpecting: %s\n' % allowed
  59. if token_history:
  60. message += '\nPrevious tokens: %s\n' % ', '.join(repr(t) for t in token_history)
  61. super(UnexpectedCharacters, self).__init__(message)
  62. class UnexpectedToken(ParseError, UnexpectedInput):
  63. def __init__(self, token, expected, considered_rules=None, state=None):
  64. self.token = token
  65. self.expected = expected # XXX str shouldn't necessary
  66. self.line = getattr(token, 'line', '?')
  67. self.column = getattr(token, 'column', '?')
  68. self.considered_rules = considered_rules
  69. self.state = state
  70. self.pos_in_stream = getattr(token, 'pos_in_stream', None)
  71. message = ("Unexpected token %r at line %s, column %s.\n"
  72. "Expected one of: \n\t* %s\n"
  73. % (token, self.line, self.column, '\n\t* '.join(self.expected)))
  74. super(UnexpectedToken, self).__init__(message)
  75. class VisitError(LarkError):
  76. """VisitError is raised when visitors are interrupted by an exception
  77. It provides the following attributes for inspection:
  78. - obj: the tree node or token it was processing when the exception was raised
  79. - orig_exc: the exception that cause it to fail
  80. """
  81. def __init__(self, rule, obj, orig_exc):
  82. self.obj = obj
  83. self.orig_exc = orig_exc
  84. message = 'Error trying to process rule "%s":\n\n%s' % (rule, orig_exc)
  85. super(VisitError, self).__init__(message)
  86. ###}