This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

142 linhas
4.0 KiB

  1. import re
  2. import sys
  3. from .utils import get_regexp_width
  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. if not self.state:
  36. return None
  37. candidate = None
  38. for label,example in examples.items():
  39. if not isinstance(example, (tuple, list)):
  40. example = [example]
  41. for malformed in example:
  42. try:
  43. parse_fn(malformed)
  44. except UnexpectedToken as ut:
  45. if ut.state == self.state:
  46. if ut.token == self.token:
  47. return label
  48. elif not candidate:
  49. candidate = label
  50. except:
  51. pass
  52. return candidate
  53. ###}
  54. class LexerConf:
  55. def __init__(self, tokens, ignore=(), postlex=None, callbacks=None):
  56. self.tokens = tokens
  57. self.ignore = ignore
  58. self.postlex = postlex
  59. self.callbacks = callbacks or {}
  60. class ParserConf:
  61. def __init__(self, rules, callback, start):
  62. self.rules = rules
  63. self.callback = callback
  64. self.start = start
  65. class Pattern(object):
  66. def __init__(self, value, flags=()):
  67. self.value = value
  68. self.flags = frozenset(flags)
  69. def __repr__(self):
  70. return repr(self.to_regexp())
  71. # Pattern Hashing assumes all subclasses have a different priority!
  72. def __hash__(self):
  73. return hash((type(self), self.value, self.flags))
  74. def __eq__(self, other):
  75. return type(self) == type(other) and self.value == other.value and self.flags == other.flags
  76. if Py36:
  77. # Python 3.6 changed syntax for flags in regular expression
  78. def _get_flags(self, value):
  79. for f in self.flags:
  80. value = ('(?%s:%s)' % (f, value))
  81. return value
  82. else:
  83. def _get_flags(self, value):
  84. for f in self.flags:
  85. value = ('(?%s)' % f) + value
  86. return value
  87. class PatternStr(Pattern):
  88. def to_regexp(self):
  89. return self._get_flags(re.escape(self.value))
  90. @property
  91. def min_width(self):
  92. return len(self.value)
  93. max_width = min_width
  94. class PatternRE(Pattern):
  95. def to_regexp(self):
  96. return self._get_flags(self.value)
  97. @property
  98. def min_width(self):
  99. return get_regexp_width(self.to_regexp())[0]
  100. @property
  101. def max_width(self):
  102. return get_regexp_width(self.to_regexp())[1]
  103. class TokenDef(object):
  104. def __init__(self, name, pattern, priority=1):
  105. assert isinstance(pattern, Pattern), pattern
  106. self.name = name
  107. self.pattern = pattern
  108. self.priority = priority
  109. def __repr__(self):
  110. return '%s(%r, %r)' % (type(self).__name__, self.name, self.pattern)