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.

139 lines
5.3 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, print_debug_info=True):
  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. if isinstance(examples, dict):
  37. examples = examples.items()
  38. candidate = (None, False)
  39. for i, (label, example) in enumerate(examples):
  40. assert not isinstance(example, STRING_TYPE)
  41. for j, malformed in enumerate(example):
  42. try:
  43. parse_fn(malformed)
  44. except UnexpectedInput as ut:
  45. if ut.state == self.state and ut.accepts == self.accepts:
  46. try:
  47. if ut.token == self.token: # Try exact match first
  48. if print_debug_info:
  49. print("Exact Match at %d, with example %d" % (i, j), (ut.token, self.token, ut.state, self.state))
  50. return label
  51. if token_type_match_fallback:
  52. # Fallback to token types match
  53. if (ut.token.type == self.token.type) and not candidate[-1]:
  54. if print_debug_info:
  55. print("Token Type Fallback at %d, with example %d" % (i, j))
  56. candidate = label, True
  57. except AttributeError:
  58. pass
  59. if not candidate[0]:
  60. if print_debug_info:
  61. print("Defaulted at %d, with example %d" % (i, j))
  62. candidate = label, False
  63. return candidate[0]
  64. class UnexpectedCharacters(LexError, UnexpectedInput):
  65. def __init__(self, seq, lex_pos, line, column, allowed=None, considered_tokens=None, state=None, token_history=None):
  66. if isinstance(seq, bytes):
  67. message = "No terminal defined for '%s' at line %d col %d" % (seq[lex_pos:lex_pos+1].decode("ascii", "backslashreplace"), line, column)
  68. else:
  69. message = "No terminal defined for '%s' at line %d col %d" % (seq[lex_pos], line, column)
  70. self.line = line
  71. self.column = column
  72. self.allowed = allowed
  73. self.considered_tokens = considered_tokens
  74. self.pos_in_stream = lex_pos
  75. self.state = state
  76. message += '\n\n' + self.get_context(seq)
  77. if allowed:
  78. message += '\nExpecting: %s\n' % allowed
  79. if token_history:
  80. message += '\nPrevious tokens: %s\n' % ', '.join(repr(t) for t in token_history)
  81. super(UnexpectedCharacters, self).__init__(message)
  82. class UnexpectedToken(ParseError, UnexpectedInput):
  83. def __init__(self, token, expected, considered_rules=None, state=None, puppet=None, accepts=None):
  84. self.token = token
  85. self.expected = expected # XXX str shouldn't necessary
  86. self.line = getattr(token, 'line', '?')
  87. self.column = getattr(token, 'column', '?')
  88. self.considered_rules = considered_rules
  89. self.state = state
  90. self.pos_in_stream = getattr(token, 'pos_in_stream', None)
  91. self.puppet = puppet
  92. self.accepts = accepts
  93. message = ("Unexpected token %r at line %s, column %s.\n"
  94. "Expected one of: \n\t* %s\n"
  95. % (token, self.line, self.column, '\n\t* '.join(self.accepts or self.expected)))
  96. super(UnexpectedToken, self).__init__(message)
  97. class VisitError(LarkError):
  98. """VisitError is raised when visitors are interrupted by an exception
  99. It provides the following attributes for inspection:
  100. - obj: the tree node or token it was processing when the exception was raised
  101. - orig_exc: the exception that cause it to fail
  102. """
  103. def __init__(self, rule, obj, orig_exc):
  104. self.obj = obj
  105. self.orig_exc = orig_exc
  106. message = 'Error trying to process rule "%s":\n\n%s' % (rule, orig_exc)
  107. super(VisitError, self).__init__(message)
  108. ###}