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.

146 lines
4.2 KiB

  1. import re
  2. import sys
  3. from .utils import get_regexp_width, STRING_TYPE
  4. Py36 = (sys.version_info[:2] >= (3, 6))
  5. ###{standalone
  6. def is_terminal(sym):
  7. return sym.isupper()
  8. class GrammarError(Exception):
  9. pass
  10. class ParseError(Exception):
  11. pass
  12. class UnexpectedToken(ParseError):
  13. def __init__(self, token, expected, seq, index, considered_rules=None, state=None):
  14. self.token = token
  15. self.expected = expected
  16. self.line = getattr(token, 'line', '?')
  17. self.column = getattr(token, 'column', '?')
  18. self.considered_rules = considered_rules
  19. self.state = state
  20. try:
  21. context = ' '.join(['%r(%s)' % (t.value, t.type) for t in seq[index:index+5]])
  22. except AttributeError:
  23. context = seq[index:index+5]
  24. except TypeError:
  25. context = "<no context>"
  26. message = ("Unexpected token %r at line %s, column %s.\n"
  27. "Expected: %s\n"
  28. "Context: %s" % (token, self.line, self.column, expected, context))
  29. super(UnexpectedToken, self).__init__(message)
  30. def match_examples(self, parse_fn, examples):
  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, "Not supported for this exception"
  36. candidate = None
  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 UnexpectedToken as ut:
  43. if ut.state == self.state:
  44. if ut.token == self.token: # Try exact match first
  45. return label
  46. elif not candidate:
  47. candidate = label
  48. return candidate
  49. def get_context(self, text, span=10):
  50. pos = self.token.pos_in_stream
  51. start = max(pos - span, 0)
  52. end = pos + span
  53. before = text[start:pos].rsplit('\n', 1)[-1]
  54. after = text[pos:end].split('\n', 1)[0]
  55. return before + after + '\n' + ' ' * len(before) + '^\n'
  56. ###}
  57. class LexerConf:
  58. def __init__(self, tokens, ignore=(), postlex=None, callbacks=None):
  59. self.tokens = tokens
  60. self.ignore = ignore
  61. self.postlex = postlex
  62. self.callbacks = callbacks or {}
  63. class ParserConf:
  64. def __init__(self, rules, callback, start):
  65. self.rules = rules
  66. self.callback = callback
  67. self.start = start
  68. class Pattern(object):
  69. def __init__(self, value, flags=()):
  70. self.value = value
  71. self.flags = frozenset(flags)
  72. def __repr__(self):
  73. return repr(self.to_regexp())
  74. # Pattern Hashing assumes all subclasses have a different priority!
  75. def __hash__(self):
  76. return hash((type(self), self.value, self.flags))
  77. def __eq__(self, other):
  78. return type(self) == type(other) and self.value == other.value and self.flags == other.flags
  79. if Py36:
  80. # Python 3.6 changed syntax for flags in regular expression
  81. def _get_flags(self, value):
  82. for f in self.flags:
  83. value = ('(?%s:%s)' % (f, value))
  84. return value
  85. else:
  86. def _get_flags(self, value):
  87. for f in self.flags:
  88. value = ('(?%s)' % f) + value
  89. return value
  90. class PatternStr(Pattern):
  91. def to_regexp(self):
  92. return self._get_flags(re.escape(self.value))
  93. @property
  94. def min_width(self):
  95. return len(self.value)
  96. max_width = min_width
  97. class PatternRE(Pattern):
  98. def to_regexp(self):
  99. return self._get_flags(self.value)
  100. @property
  101. def min_width(self):
  102. return get_regexp_width(self.to_regexp())[0]
  103. @property
  104. def max_width(self):
  105. return get_regexp_width(self.to_regexp())[1]
  106. class TokenDef(object):
  107. def __init__(self, name, pattern, priority=1):
  108. assert isinstance(pattern, Pattern), pattern
  109. self.name = name
  110. self.pattern = pattern
  111. self.priority = priority
  112. def __repr__(self):
  113. return '%s(%r, %r)' % (type(self).__name__, self.name, self.pattern)