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.
6 #include "misc/Interval.h"
7 #include "Exceptions.h"
8 #include "support/StringUtils.h"
10 #include "UnbufferedCharStream.h"
12 using namespace antlrcpp;
13 using namespace antlr4;
14 using namespace antlr4::misc;
16 UnbufferedCharStream::UnbufferedCharStream(std::wistream &input) : _input(input) {
17 InitializeInstanceFields();
19 // The vector's size is what used to be n in Java code.
23 void UnbufferedCharStream::consume() {
25 throw IllegalStateException("cannot consume EOF");
28 // buf always has at least data[p==0] in this method due to ctor
29 _lastChar = _data[_p]; // track last char for LA(-1)
31 if (_p == _data.size() - 1 && _numMarkers == 0) {
32 size_t capacity = _data.capacity();
34 _data.reserve(capacity);
37 _lastCharBufferStart = _lastChar;
46 void UnbufferedCharStream::sync(size_t want) {
47 if (_p + want <= _data.size()) // Already enough data loaded?
50 fill(_p + want - _data.size());
53 size_t UnbufferedCharStream::fill(size_t n) {
54 for (size_t i = 0; i < n; i++) {
55 if (_data.size() > 0 && _data.back() == 0xFFFF) {
60 char32_t c = nextChar();
62 #if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023026
63 } catch (IOException &ioe) {
64 // throw_with_nested is not available before VS 2015.
67 } catch (IOException & /*ioe*/) {
68 std::throw_with_nested(RuntimeException());
76 char32_t UnbufferedCharStream::nextChar() {
82 void UnbufferedCharStream::add(char32_t c) {
86 size_t UnbufferedCharStream::LA(ssize_t i) {
87 if (i == -1) { // special case
91 // We can look back only as many chars as we have buffered.
92 ssize_t index = static_cast<ssize_t>(_p) + i - 1;
94 throw IndexOutOfBoundsException();
98 sync(static_cast<size_t>(i)); // No need to sync if we look back.
100 if (static_cast<size_t>(index) >= _data.size()) {
104 if (_data[static_cast<size_t>(index)] == 0xFFFF) {
108 return _data[static_cast<size_t>(index)];
111 ssize_t UnbufferedCharStream::mark() {
112 if (_numMarkers == 0) {
113 _lastCharBufferStart = _lastChar;
116 ssize_t mark = -static_cast<ssize_t>(_numMarkers) - 1;
121 void UnbufferedCharStream::release(ssize_t marker) {
122 ssize_t expectedMark = -static_cast<ssize_t>(_numMarkers);
123 if (marker != expectedMark) {
124 throw IllegalStateException("release() called with an invalid marker.");
128 if (_numMarkers == 0 && _p > 0) {
131 _lastCharBufferStart = _lastChar;
135 size_t UnbufferedCharStream::index() {
136 return _currentCharIndex;
139 void UnbufferedCharStream::seek(size_t index) {
140 if (index == _currentCharIndex) {
144 if (index > _currentCharIndex) {
145 sync(index - _currentCharIndex);
146 index = std::min(index, getBufferStartIndex() + _data.size() - 1);
149 // index == to bufferStartIndex should set p to 0
150 ssize_t i = static_cast<ssize_t>(index) - static_cast<ssize_t>(getBufferStartIndex());
152 throw IllegalArgumentException(std::string("cannot seek to negative index ") + std::to_string(index));
153 } else if (i >= static_cast<ssize_t>(_data.size())) {
154 throw UnsupportedOperationException("Seek to index outside buffer: " + std::to_string(index) +
155 " not in " + std::to_string(getBufferStartIndex()) + ".." +
156 std::to_string(getBufferStartIndex() + _data.size()));
159 _p = static_cast<size_t>(i);
160 _currentCharIndex = index;
162 _lastChar = _lastCharBufferStart;
164 _lastChar = _data[_p - 1];
168 size_t UnbufferedCharStream::size() {
169 throw UnsupportedOperationException("Unbuffered stream cannot know its size");
172 std::string UnbufferedCharStream::getSourceName() const {
174 return UNKNOWN_SOURCE_NAME;
180 std::string UnbufferedCharStream::getText(const misc::Interval &interval) {
181 if (interval.a < 0 || interval.b >= interval.a - 1) {
182 throw IllegalArgumentException("invalid interval");
185 size_t bufferStartIndex = getBufferStartIndex();
186 if (!_data.empty() && _data.back() == 0xFFFF) {
187 if (interval.a + interval.length() > bufferStartIndex + _data.size()) {
188 throw IllegalArgumentException("the interval extends past the end of the stream");
192 if (interval.a < static_cast<ssize_t>(bufferStartIndex) || interval.b >= ssize_t(bufferStartIndex + _data.size())) {
193 throw UnsupportedOperationException("interval " + interval.toString() + " outside buffer: " +
194 std::to_string(bufferStartIndex) + ".." + std::to_string(bufferStartIndex + _data.size() - 1));
196 // convert from absolute to local index
197 size_t i = interval.a - bufferStartIndex;
198 return utf32_to_utf8(_data.substr(i, interval.length()));
201 size_t UnbufferedCharStream::getBufferStartIndex() const {
202 return _currentCharIndex - _p;
205 void UnbufferedCharStream::InitializeInstanceFields() {
209 _lastCharBufferStart = 0;
210 _currentCharIndex = 0;