blob: 2dded4091090da87e28d98caed79296d5ad65578 [file] [log] [blame]
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include <string.h>
#include "Exceptions.h"
#include "misc/Interval.h"
#include "IntStream.h"
#include "support/StringUtils.h"
#include "support/CPPUtils.h"
#include "ANTLRInputStream.h"
using namespace antlr4;
using namespace antlrcpp;
using misc::Interval;
ANTLRInputStream::ANTLRInputStream() {
InitializeInstanceFields();
}
#if __cplusplus >= 201703L
ANTLRInputStream::ANTLRInputStream(const std::string_view &input): ANTLRInputStream() {
load(input.data(), input.length());
}
#endif
ANTLRInputStream::ANTLRInputStream(const std::string &input): ANTLRInputStream() {
load(input.data(), input.size());
}
ANTLRInputStream::ANTLRInputStream(const char *data, size_t length) {
load(data, length);
}
ANTLRInputStream::ANTLRInputStream(std::istream &stream): ANTLRInputStream() {
load(stream);
}
void ANTLRInputStream::load(const std::string &input) {
load(input.data(), input.size());
}
void ANTLRInputStream::load(const char *data, size_t length) {
// Remove the UTF-8 BOM if present.
const char *bom = "\xef\xbb\xbf";
if (length >= 3 && strncmp(data, bom, 3) == 0)
_data = antlrcpp::utf8_to_utf32(data + 3, data + length);
else
_data = antlrcpp::utf8_to_utf32(data, data + length);
p = 0;
}
void ANTLRInputStream::load(std::istream &stream) {
if (!stream.good() || stream.eof()) // No fail, bad or EOF.
return;
_data.clear();
std::string s((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
load(s.data(), s.length());
}
void ANTLRInputStream::reset() {
p = 0;
}
void ANTLRInputStream::consume() {
if (p >= _data.size()) {
assert(LA(1) == IntStream::EOF);
throw IllegalStateException("cannot consume EOF");
}
if (p < _data.size()) {
p++;
}
}
size_t ANTLRInputStream::LA(ssize_t i) {
if (i == 0) {
return 0; // undefined
}
ssize_t position = static_cast<ssize_t>(p);
if (i < 0) {
i++; // e.g., translate LA(-1) to use offset i=0; then _data[p+0-1]
if ((position + i - 1) < 0) {
return IntStream::EOF; // invalid; no char before first char
}
}
if ((position + i - 1) >= static_cast<ssize_t>(_data.size())) {
return IntStream::EOF;
}
return _data[static_cast<size_t>((position + i - 1))];
}
size_t ANTLRInputStream::LT(ssize_t i) {
return LA(i);
}
size_t ANTLRInputStream::index() {
return p;
}
size_t ANTLRInputStream::size() {
return _data.size();
}
// Mark/release do nothing. We have entire buffer.
ssize_t ANTLRInputStream::mark() {
return -1;
}
void ANTLRInputStream::release(ssize_t /* marker */) {
}
void ANTLRInputStream::seek(size_t index) {
if (index <= p) {
p = index; // just jump; don't update stream state (line, ...)
return;
}
// seek forward, consume until p hits index or n (whichever comes first)
index = std::min(index, _data.size());
while (p < index) {
consume();
}
}
std::string ANTLRInputStream::getText(const Interval &interval) {
if (interval.a < 0 || interval.b < 0) {
return "";
}
size_t start = static_cast<size_t>(interval.a);
size_t stop = static_cast<size_t>(interval.b);
if (stop >= _data.size()) {
stop = _data.size() - 1;
}
size_t count = stop - start + 1;
if (start >= _data.size()) {
return "";
}
return antlrcpp::utf32_to_utf8(_data.substr(start, count));
}
std::string ANTLRInputStream::getSourceName() const {
if (name.empty()) {
return IntStream::UNKNOWN_SOURCE_NAME;
}
return name;
}
std::string ANTLRInputStream::toString() const {
return antlrcpp::utf32_to_utf8(_data);
}
void ANTLRInputStream::InitializeInstanceFields() {
p = 0;
}