]> gitweb.ps.run Git - toc/blob - antlr4-cpp-runtime-4.9.2-source/runtime/src/UnbufferedTokenStream.cpp
add antlr source code and ReadMe
[toc] / antlr4-cpp-runtime-4.9.2-source / runtime / src / UnbufferedTokenStream.cpp
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.
4  */
5
6 #include "Token.h"
7 #include "Exceptions.h"
8 #include "assert.h"
9 #include "TokenSource.h"
10 #include "support/Arrays.h"
11 #include "misc/Interval.h"
12 #include "RuleContext.h"
13 #include "WritableToken.h"
14
15 #include "UnbufferedTokenStream.h"
16
17 using namespace antlr4;
18
19 UnbufferedTokenStream::UnbufferedTokenStream(TokenSource *tokenSource) : UnbufferedTokenStream(tokenSource, 256) {
20 }
21
22 UnbufferedTokenStream::UnbufferedTokenStream(TokenSource *tokenSource, int /*bufferSize*/)
23   : _tokenSource(tokenSource), _lastToken(nullptr), _lastTokenBufferStart(nullptr)
24 {
25   InitializeInstanceFields();
26   fill(1); // prime the pump
27 }
28
29 UnbufferedTokenStream::~UnbufferedTokenStream() {
30 }
31
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()));
38   }
39   return _tokens[i - bufferStartIndex].get();
40 }
41
42 Token* UnbufferedTokenStream::LT(ssize_t i)
43 {
44   if (i == -1) {
45     return _lastToken;
46   }
47
48   sync(i);
49   ssize_t index = static_cast<ssize_t>(_p) + i - 1;
50   if (index < 0) {
51     throw IndexOutOfBoundsException(std::string("LT(") + std::to_string(i) + std::string(") gives negative index"));
52   }
53
54   if (index >= static_cast<ssize_t>(_tokens.size())) {
55     assert(_tokens.size() > 0 && _tokens.back()->getType() == EOF);
56     return _tokens.back().get();
57   }
58
59   return _tokens[static_cast<size_t>(index)].get();
60 }
61
62 size_t UnbufferedTokenStream::LA(ssize_t i)
63 {
64   return LT(i)->getType();
65 }
66
67 TokenSource* UnbufferedTokenStream::getTokenSource() const
68 {
69   return _tokenSource;
70 }
71
72 std::string UnbufferedTokenStream::getText()
73 {
74   return "";
75 }
76
77 std::string UnbufferedTokenStream::getText(RuleContext* ctx)
78 {
79   return getText(ctx->getSourceInterval());
80 }
81
82 std::string UnbufferedTokenStream::getText(Token *start, Token *stop)
83 {
84   return getText(misc::Interval(start->getTokenIndex(), stop->getTokenIndex()));
85 }
86
87 void UnbufferedTokenStream::consume()
88 {
89   if (LA(1) == EOF) {
90     throw IllegalStateException("cannot consume EOF");
91   }
92
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)
95
96   // if we're at last token and no markers, opportunity to flush buffer
97   if (_p == _tokens.size() - 1 && _numMarkers == 0) {
98     _tokens.clear();
99     _p = 0;
100     _lastTokenBufferStart = _lastToken;
101   } else {
102     ++_p;
103   }
104
105   ++_currentTokenIndex;
106   sync(1);
107 }
108
109 /// <summary>
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}.
113 /// </summary>
114 void UnbufferedTokenStream::sync(ssize_t want)
115 {
116   ssize_t need = (static_cast<ssize_t>(_p) + want - 1) - static_cast<ssize_t>(_tokens.size()) + 1; // how many more elements we need?
117   if (need > 0) {
118     fill(static_cast<size_t>(need));
119   }
120 }
121
122 /// <summary>
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.
126 /// </summary>
127 size_t UnbufferedTokenStream::fill(size_t n)
128 {
129   for (size_t i = 0; i < n; i++) {
130     if (_tokens.size() > 0 && _tokens.back()->getType() == EOF) {
131       return i;
132     }
133
134     add(_tokenSource->nextToken());
135   }
136
137   return n;
138 }
139
140 void UnbufferedTokenStream::add(std::unique_ptr<Token> t)
141 {
142   WritableToken *writable = dynamic_cast<WritableToken *>(t.get());
143   if (writable != nullptr) {
144     writable->setTokenIndex(int(getBufferStartIndex() + _tokens.size()));
145   }
146
147   _tokens.push_back(std::move(t));
148 }
149
150 /// <summary>
151 /// Return a marker that we can release later.
152 /// <p/>
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.
156 /// </summary>
157 ssize_t UnbufferedTokenStream::mark()
158 {
159   if (_numMarkers == 0) {
160     _lastTokenBufferStart = _lastToken;
161   }
162
163   int mark = -_numMarkers - 1;
164   _numMarkers++;
165   return mark;
166 }
167
168 void UnbufferedTokenStream::release(ssize_t marker)
169 {
170   ssize_t expectedMark = -_numMarkers;
171   if (marker != expectedMark) {
172     throw IllegalStateException("release() called with an invalid marker.");
173   }
174
175   _numMarkers--;
176   if (_numMarkers == 0) { // can we release buffer?
177     if (_p > 0) {
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));
181       _p = 0;
182     }
183
184     _lastTokenBufferStart = _lastToken;
185   }
186 }
187
188 size_t UnbufferedTokenStream::index()
189 {
190   return _currentTokenIndex;
191 }
192
193 void UnbufferedTokenStream::seek(size_t index)
194 { // seek to absolute index
195   if (index == _currentTokenIndex) {
196     return;
197   }
198
199   if (index > _currentTokenIndex) {
200     sync(ssize_t(index - _currentTokenIndex));
201     index = std::min(index, getBufferStartIndex() + _tokens.size() - 1);
202   }
203
204   size_t bufferStartIndex = getBufferStartIndex();
205   if (bufferStartIndex > index) {
206     throw IllegalArgumentException(std::string("cannot seek to negative index ") + std::to_string(index));
207   }
208
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()));
213   }
214
215   _p = i;
216   _currentTokenIndex = index;
217   if (_p == 0) {
218     _lastToken = _lastTokenBufferStart;
219   } else {
220     _lastToken = _tokens[_p - 1].get();
221   }
222 }
223
224 size_t UnbufferedTokenStream::size()
225 {
226   throw UnsupportedOperationException("Unbuffered stream cannot know its size");
227 }
228
229 std::string UnbufferedTokenStream::getSourceName() const
230 {
231   return _tokenSource->getSourceName();
232 }
233
234 std::string UnbufferedTokenStream::getText(const misc::Interval &interval)
235 {
236   size_t bufferStartIndex = getBufferStartIndex();
237   size_t bufferStopIndex = bufferStartIndex + _tokens.size() - 1;
238
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));
244   }
245
246   size_t a = start - bufferStartIndex;
247   size_t b = stop - bufferStartIndex;
248
249   std::stringstream ss;
250   for (size_t i = a; i <= b; i++) {
251     Token *t = _tokens[i].get();
252     if (i > 0)
253       ss << ", ";
254     ss << t->getText();
255   }
256
257   return ss.str();
258 }
259
260 size_t UnbufferedTokenStream::getBufferStartIndex() const
261 {
262   return _currentTokenIndex - _p;
263 }
264
265 void UnbufferedTokenStream::InitializeInstanceFields()
266 {
267   _p = 0;
268   _numMarkers = 0;
269   _currentTokenIndex = 0;
270 }