ListTokenSource.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #
  2. # Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
  3. # Use of this file is governed by the BSD 3-clause license that
  4. # can be found in the LICENSE.txt file in the project root.
  5. #
  6. #
  7. # Provides an implementation of {@link TokenSource} as a wrapper around a list
  8. # of {@link Token} objects.
  9. #
  10. # <p>If the final token in the list is an {@link Token#EOF} token, it will be used
  11. # as the EOF token for every call to {@link #nextToken} after the end of the
  12. # list is reached. Otherwise, an EOF token will be created.</p>
  13. #
  14. from antlr4.CommonTokenFactory import CommonTokenFactory
  15. from antlr4.Lexer import TokenSource
  16. from antlr4.Token import Token
  17. class ListTokenSource(TokenSource):
  18. __slots__ = ('tokens', 'sourceName', 'pos', 'eofToken', '_factory')
  19. # Constructs a new {@link ListTokenSource} instance from the specified
  20. # collection of {@link Token} objects and source name.
  21. #
  22. # @param tokens The collection of {@link Token} objects to provide as a
  23. # {@link TokenSource}.
  24. # @param sourceName The name of the {@link TokenSource}. If this value is
  25. # {@code null}, {@link #getSourceName} will attempt to infer the name from
  26. # the next {@link Token} (or the previous token if the end of the input has
  27. # been reached).
  28. #
  29. # @exception NullPointerException if {@code tokens} is {@code null}
  30. #
  31. def __init__(self, tokens:list, sourceName:str=None):
  32. if tokens is None:
  33. raise ReferenceError("tokens cannot be null")
  34. self.tokens = tokens
  35. self.sourceName = sourceName
  36. # The index into {@link #tokens} of token to return by the next call to
  37. # {@link #nextToken}. The end of the input is indicated by this value
  38. # being greater than or equal to the number of items in {@link #tokens}.
  39. self.pos = 0
  40. # This field caches the EOF token for the token source.
  41. self.eofToken = None
  42. # This is the backing field for {@link #getTokenFactory} and
  43. self._factory = CommonTokenFactory.DEFAULT
  44. #
  45. # {@inheritDoc}
  46. #
  47. @property
  48. def column(self):
  49. if self.pos < len(self.tokens):
  50. return self.tokens[self.pos].column
  51. elif self.eofToken is not None:
  52. return self.eofToken.column
  53. elif len(self.tokens) > 0:
  54. # have to calculate the result from the line/column of the previous
  55. # token, along with the text of the token.
  56. lastToken = self.tokens[len(self.tokens) - 1]
  57. tokenText = lastToken.text
  58. if tokenText is not None:
  59. lastNewLine = tokenText.rfind('\n')
  60. if lastNewLine >= 0:
  61. return len(tokenText) - lastNewLine - 1
  62. return lastToken.column + lastToken.stop - lastToken.start + 1
  63. # only reach this if tokens is empty, meaning EOF occurs at the first
  64. # position in the input
  65. return 0
  66. #
  67. # {@inheritDoc}
  68. #
  69. def nextToken(self):
  70. if self.pos >= len(self.tokens):
  71. if self.eofToken is None:
  72. start = -1
  73. if len(self.tokens) > 0:
  74. previousStop = self.tokens[len(self.tokens) - 1].stop
  75. if previousStop != -1:
  76. start = previousStop + 1
  77. stop = max(-1, start - 1)
  78. self.eofToken = self._factory.create((self, self.getInputStream()),
  79. Token.EOF, "EOF", Token.DEFAULT_CHANNEL, start, stop, self.line, self.column)
  80. return self.eofToken
  81. t = self.tokens[self.pos]
  82. if self.pos == len(self.tokens) - 1 and t.type == Token.EOF:
  83. self.eofToken = t
  84. self.pos += 1
  85. return t
  86. #
  87. # {@inheritDoc}
  88. #
  89. @property
  90. def line(self):
  91. if self.pos < len(self.tokens):
  92. return self.tokens[self.pos].line
  93. elif self.eofToken is not None:
  94. return self.eofToken.line
  95. elif len(self.tokens) > 0:
  96. # have to calculate the result from the line/column of the previous
  97. # token, along with the text of the token.
  98. lastToken = self.tokens[len(self.tokens) - 1]
  99. line = lastToken.line
  100. tokenText = lastToken.text
  101. if tokenText is not None:
  102. line += tokenText.count('\n')
  103. # if no text is available, assume the token did not contain any newline characters.
  104. return line
  105. # only reach this if tokens is empty, meaning EOF occurs at the first
  106. # position in the input
  107. return 1
  108. #
  109. # {@inheritDoc}
  110. #
  111. def getInputStream(self):
  112. if self.pos < len(self.tokens):
  113. return self.tokens[self.pos].getInputStream()
  114. elif self.eofToken is not None:
  115. return self.eofToken.getInputStream()
  116. elif len(self.tokens) > 0:
  117. return self.tokens[len(self.tokens) - 1].getInputStream()
  118. else:
  119. # no input stream information is available
  120. return None
  121. #
  122. # {@inheritDoc}
  123. #
  124. def getSourceName(self):
  125. if self.sourceName is not None:
  126. return self.sourceName
  127. inputStream = self.getInputStream()
  128. if inputStream is not None:
  129. return inputStream.getSourceName()
  130. else:
  131. return "List"