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.

72 lines
2.1 KiB

  1. "Provides Indentation services for languages with indentation similar to Python"
  2. from .exceptions import LarkError
  3. from .lark import PostLex
  4. from .lexer import Token
  5. ###{standalone
  6. class DedentError(LarkError):
  7. pass
  8. class Indenter(PostLex):
  9. OPEN_PAREN_types: list
  10. CLOSE_PAREN_types: list
  11. DEDENT_type: str
  12. def __init__(self):
  13. self.paren_level = None
  14. self.indent_level = None
  15. assert self.tab_len > 0
  16. def handle_NL(self, token):
  17. if self.paren_level > 0:
  18. return
  19. yield token
  20. indent_str = token.rsplit('\n', 1)[1] # Tabs and spaces
  21. indent = indent_str.count(' ') + indent_str.count('\t') * self.tab_len
  22. if indent > self.indent_level[-1]:
  23. self.indent_level.append(indent)
  24. yield Token.new_borrow_pos(self.INDENT_type, indent_str, token)
  25. else:
  26. while indent < self.indent_level[-1]:
  27. self.indent_level.pop()
  28. yield Token.new_borrow_pos(self.DEDENT_type, indent_str, token)
  29. if indent != self.indent_level[-1]:
  30. raise DedentError('Unexpected dedent to column %s. Expected dedent to %s' % (indent, self.indent_level[-1]))
  31. def _process(self, stream):
  32. for token in stream:
  33. if token.type == self.NL_type:
  34. for t in self.handle_NL(token):
  35. yield t
  36. else:
  37. yield token
  38. if token.type in self.OPEN_PAREN_types:
  39. self.paren_level += 1
  40. elif token.type in self.CLOSE_PAREN_types:
  41. self.paren_level -= 1
  42. assert self.paren_level >= 0
  43. while len(self.indent_level) > 1:
  44. self.indent_level.pop()
  45. yield Token(self.DEDENT_type, '')
  46. assert self.indent_level == [0], self.indent_level
  47. def process(self, stream):
  48. self.paren_level = 0
  49. self.indent_level = [0]
  50. return self._process(stream)
  51. # XXX Hack for ContextualLexer. Maybe there's a more elegant solution?
  52. @property
  53. def always_accept(self):
  54. return (self.NL_type,)
  55. ###}