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.

129 lines
4.7 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. if not isinstance(text, bytes):
  23. before = text[start:pos].rsplit('\n', 1)[-1]
  24. after = text[pos:end].split('\n', 1)[0]
  25. return before + after + '\n' + ' ' * len(before) + '^\n'
  26. else:
  27. before = text[start:pos].rsplit(b'\n', 1)[-1]
  28. after = text[pos:end].split(b'\n', 1)[0]
  29. return (before + after + b'\n' + b' ' * len(before) + b'^\n').decode("ascii", "backslashreplace")
  30. def match_examples(self, parse_fn, examples, token_type_match_fallback=False):
  31. """ Given a parser instance and a dictionary mapping some label with
  32. some malformed syntax examples, it'll return the label for the
  33. example that bests matches the current error.
  34. """
  35. assert self.state is not None, "Not supported for this exception"
  36. candidate = (None, False)
  37. for label, example in examples.items():
  38. assert not isinstance(example, STRING_TYPE)
  39. for malformed in example:
  40. try:
  41. parse_fn(malformed)
  42. except UnexpectedInput as ut:
  43. if ut.state == self.state:
  44. try:
  45. if ut.token == self.token: # Try exact match first
  46. return label
  47. if token_type_match_fallback:
  48. # Fallback to token types match
  49. if (ut.token.type == self.token.type) and not candidate[-1]:
  50. candidate = label, True
  51. except AttributeError:
  52. pass
  53. if not candidate[0]:
  54. candidate = label, False
  55. return candidate[0]
  56. class UnexpectedCharacters(LexError, UnexpectedInput):
  57. def __init__(self, seq, lex_pos, line, column, allowed=None, considered_tokens=None, state=None, token_history=None):
  58. if isinstance(seq, bytes):
  59. message = "No terminal defined for '%s' at line %d col %d" % (seq[lex_pos:lex_pos+1].decode("ascii", "backslashreplace"), line, column)
  60. else:
  61. message = "No terminal defined for '%s' at line %d col %d" % (seq[lex_pos], line, column)
  62. self.line = line
  63. self.column = column
  64. self.allowed = allowed
  65. self.considered_tokens = considered_tokens
  66. self.pos_in_stream = lex_pos
  67. self.state = state
  68. message += '\n\n' + self.get_context(seq)
  69. if allowed:
  70. message += '\nExpecting: %s\n' % allowed
  71. if token_history:
  72. message += '\nPrevious tokens: %s\n' % ', '.join(repr(t) for t in token_history)
  73. super(UnexpectedCharacters, self).__init__(message)
  74. class UnexpectedToken(ParseError, UnexpectedInput):
  75. def __init__(self, token, expected, considered_rules=None, state=None, puppet=None):
  76. self.token = token
  77. self.expected = expected # XXX str shouldn't necessary
  78. self.line = getattr(token, 'line', '?')
  79. self.column = getattr(token, 'column', '?')
  80. self.considered_rules = considered_rules
  81. self.state = state
  82. self.pos_in_stream = getattr(token, 'pos_in_stream', None)
  83. self.puppet = puppet
  84. message = ("Unexpected token %r at line %s, column %s.\n"
  85. "Expected one of: \n\t* %s\n"
  86. % (token, self.line, self.column, '\n\t* '.join(self.expected)))
  87. super(UnexpectedToken, self).__init__(message)
  88. class VisitError(LarkError):
  89. """VisitError is raised when visitors are interrupted by an exception
  90. It provides the following attributes for inspection:
  91. - obj: the tree node or token it was processing when the exception was raised
  92. - orig_exc: the exception that cause it to fail
  93. """
  94. def __init__(self, rule, obj, orig_exc):
  95. self.obj = obj
  96. self.orig_exc = orig_exc
  97. message = 'Error trying to process rule "%s":\n\n%s' % (rule, orig_exc)
  98. super(VisitError, self).__init__(message)
  99. ###}