1 /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 * Use of this file is governed by the BSD 3-clause license that
3 * can be found in the LICENSE.txt file in the project root.
7 #include "Exceptions.h"
9 #include "TokenSource.h"
10 #include "support/Arrays.h"
11 #include "misc/Interval.h"
12 #include "RuleContext.h"
13 #include "WritableToken.h"
15 #include "UnbufferedTokenStream.h"
17 using namespace antlr4;
19 UnbufferedTokenStream::UnbufferedTokenStream(TokenSource *tokenSource) : UnbufferedTokenStream(tokenSource, 256) {
22 UnbufferedTokenStream::UnbufferedTokenStream(TokenSource *tokenSource, int /*bufferSize*/)
23 : _tokenSource(tokenSource), _lastToken(nullptr), _lastTokenBufferStart(nullptr)
25 InitializeInstanceFields();
26 fill(1); // prime the pump
29 UnbufferedTokenStream::~UnbufferedTokenStream() {
32 Token* UnbufferedTokenStream::get(size_t i) const
33 { // get absolute index
34 size_t bufferStartIndex = getBufferStartIndex();
35 if (i < bufferStartIndex || i >= bufferStartIndex + _tokens.size()) {
36 throw IndexOutOfBoundsException(std::string("get(") + std::to_string(i) + std::string(") outside buffer: ")
37 + std::to_string(bufferStartIndex) + std::string("..") + std::to_string(bufferStartIndex + _tokens.size()));
39 return _tokens[i - bufferStartIndex].get();
42 Token* UnbufferedTokenStream::LT(ssize_t i)
49 ssize_t index = static_cast<ssize_t>(_p) + i - 1;
51 throw IndexOutOfBoundsException(std::string("LT(") + std::to_string(i) + std::string(") gives negative index"));
54 if (index >= static_cast<ssize_t>(_tokens.size())) {
55 assert(_tokens.size() > 0 && _tokens.back()->getType() == EOF);
56 return _tokens.back().get();
59 return _tokens[static_cast<size_t>(index)].get();
62 size_t UnbufferedTokenStream::LA(ssize_t i)
64 return LT(i)->getType();
67 TokenSource* UnbufferedTokenStream::getTokenSource() const
72 std::string UnbufferedTokenStream::getText()
77 std::string UnbufferedTokenStream::getText(RuleContext* ctx)
79 return getText(ctx->getSourceInterval());
82 std::string UnbufferedTokenStream::getText(Token *start, Token *stop)
84 return getText(misc::Interval(start->getTokenIndex(), stop->getTokenIndex()));
87 void UnbufferedTokenStream::consume()
90 throw IllegalStateException("cannot consume EOF");
93 // buf always has at least tokens[p==0] in this method due to ctor
94 _lastToken = _tokens[_p].get(); // track last token for LT(-1)
96 // if we're at last token and no markers, opportunity to flush buffer
97 if (_p == _tokens.size() - 1 && _numMarkers == 0) {
100 _lastTokenBufferStart = _lastToken;
105 ++_currentTokenIndex;
110 /// Make sure we have 'need' elements from current position <seealso cref="#p p"/>. Last valid
111 /// {@code p} index is {@code tokens.length-1}. {@code p+need-1} is the tokens index 'need' elements
112 /// ahead. If we need 1 element, {@code (p+1-1)==p} must be less than {@code tokens.length}.
114 void UnbufferedTokenStream::sync(ssize_t want)
116 ssize_t need = (static_cast<ssize_t>(_p) + want - 1) - static_cast<ssize_t>(_tokens.size()) + 1; // how many more elements we need?
118 fill(static_cast<size_t>(need));
123 /// Add {@code n} elements to the buffer. Returns the number of tokens
124 /// actually added to the buffer. If the return value is less than {@code n},
125 /// then EOF was reached before {@code n} tokens could be added.
127 size_t UnbufferedTokenStream::fill(size_t n)
129 for (size_t i = 0; i < n; i++) {
130 if (_tokens.size() > 0 && _tokens.back()->getType() == EOF) {
134 add(_tokenSource->nextToken());
140 void UnbufferedTokenStream::add(std::unique_ptr<Token> t)
142 WritableToken *writable = dynamic_cast<WritableToken *>(t.get());
143 if (writable != nullptr) {
144 writable->setTokenIndex(int(getBufferStartIndex() + _tokens.size()));
147 _tokens.push_back(std::move(t));
151 /// Return a marker that we can release later.
153 /// The specific marker value used for this class allows for some level of
154 /// protection against misuse where {@code seek()} is called on a mark or
155 /// {@code release()} is called in the wrong order.
157 ssize_t UnbufferedTokenStream::mark()
159 if (_numMarkers == 0) {
160 _lastTokenBufferStart = _lastToken;
163 int mark = -_numMarkers - 1;
168 void UnbufferedTokenStream::release(ssize_t marker)
170 ssize_t expectedMark = -_numMarkers;
171 if (marker != expectedMark) {
172 throw IllegalStateException("release() called with an invalid marker.");
176 if (_numMarkers == 0) { // can we release buffer?
178 // Copy tokens[p]..tokens[n-1] to tokens[0]..tokens[(n-1)-p], reset ptrs
179 // p is last valid token; move nothing if p==n as we have no valid char
180 _tokens.erase(_tokens.begin(), _tokens.begin() + static_cast<ssize_t>(_p));
184 _lastTokenBufferStart = _lastToken;
188 size_t UnbufferedTokenStream::index()
190 return _currentTokenIndex;
193 void UnbufferedTokenStream::seek(size_t index)
194 { // seek to absolute index
195 if (index == _currentTokenIndex) {
199 if (index > _currentTokenIndex) {
200 sync(ssize_t(index - _currentTokenIndex));
201 index = std::min(index, getBufferStartIndex() + _tokens.size() - 1);
204 size_t bufferStartIndex = getBufferStartIndex();
205 if (bufferStartIndex > index) {
206 throw IllegalArgumentException(std::string("cannot seek to negative index ") + std::to_string(index));
209 size_t i = index - bufferStartIndex;
210 if (i >= _tokens.size()) {
211 throw UnsupportedOperationException(std::string("seek to index outside buffer: ") + std::to_string(index) +
212 " not in " + std::to_string(bufferStartIndex) + ".." + std::to_string(bufferStartIndex + _tokens.size()));
216 _currentTokenIndex = index;
218 _lastToken = _lastTokenBufferStart;
220 _lastToken = _tokens[_p - 1].get();
224 size_t UnbufferedTokenStream::size()
226 throw UnsupportedOperationException("Unbuffered stream cannot know its size");
229 std::string UnbufferedTokenStream::getSourceName() const
231 return _tokenSource->getSourceName();
234 std::string UnbufferedTokenStream::getText(const misc::Interval &interval)
236 size_t bufferStartIndex = getBufferStartIndex();
237 size_t bufferStopIndex = bufferStartIndex + _tokens.size() - 1;
239 size_t start = interval.a;
240 size_t stop = interval.b;
241 if (start < bufferStartIndex || stop > bufferStopIndex) {
242 throw UnsupportedOperationException(std::string("interval ") + interval.toString() +
243 " not in token buffer window: " + std::to_string(bufferStartIndex) + ".." + std::to_string(bufferStopIndex));
246 size_t a = start - bufferStartIndex;
247 size_t b = stop - bufferStartIndex;
249 std::stringstream ss;
250 for (size_t i = a; i <= b; i++) {
251 Token *t = _tokens[i].get();
260 size_t UnbufferedTokenStream::getBufferStartIndex() const
262 return _currentTokenIndex - _p;
265 void UnbufferedTokenStream::InitializeInstanceFields()
269 _currentTokenIndex = 0;