This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

105 Zeilen
2.8 KiB

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