#include "LuaParser/File/LuaSource.h"
#include "Util/Utf8.h"
std::shared_ptr<LuaSource> LuaSource::From(std::string &&source) {
return std::make_shared<LuaSource>(std::move(source));
}
LuaSource::LuaSource(std::string &&fileText)
: _source(fileText),
_linenumber(0),
_lineState(EndOfLine::UNKNOWN) {
_lineOffsetVec.push_back(0);
}
std::size_t LuaSource::GetLine(std::size_t offset) const {
if (_lineOffsetVec.empty()) {
return 0;
}
int maxLine = static_cast<int>(_lineOffsetVec.size()) - 1;
int targetLine = maxLine;
int upperLine = maxLine;
int lowestLine = 0;
while (true) {
if (_lineOffsetVec[targetLine] > offset) {
upperLine = targetLine;
targetLine = (upperLine + lowestLine) / 2;
if (targetLine == 0) {
return targetLine;
}
} else {
if (upperLine - targetLine <= 1) {
return targetLine;
}
lowestLine = targetLine;
targetLine = (upperLine + lowestLine) / 2;
}
}
return 0;
}
std::size_t LuaSource::GetColumn(std::size_t offset) const {
auto line = GetLine(offset);
auto lineStartOffset = _lineOffsetVec[line];
if (offset > lineStartOffset) {
auto bytesLength = offset - lineStartOffset;
return utf8::Utf8nLen(_source.data() + lineStartOffset,
bytesLength);
}
return 0;
}
bool LuaSource::CheckNonUniformCharBefore(std::size_t offset) const {
auto line = GetLine(offset);
auto lineStartOffset = _lineOffsetVec[line];
if (offset > lineStartOffset) {
std::size_t byteNum = 0;
for (std::size_t i = lineStartOffset; i < offset; i += byteNum) {
auto codepoint = utf8::Utf8ToUnicode(_source.data() + i, _source.size() - i, byteNum);
if (codepoint > 0x24F) {
return true;
}
}
}
return false;
}
std::size_t LuaSource::GetLineOffset(std::size_t offset) const {
auto line = GetLine(offset);
auto lineStartOffset = _lineOffsetVec[line];
if (offset > lineStartOffset) {
return offset - lineStartOffset;
}
return 0;
}
std::size_t LuaSource::GetOffset(std::size_t line, std::size_t character) const {
std::size_t sizeLine = line;
if (sizeLine >= _lineOffsetVec.size()) {
return _source.size() + 1;
}
auto lineStartOffset = _lineOffsetVec[line];
std::size_t nextOffset = 0;
if (sizeLine + 1 >= _lineOffsetVec.size()) {
nextOffset = _source.size();
} else {
nextOffset = _lineOffsetVec[line + 1];
}
std::size_t offset = utf8::Utf8nByteNum(_source.data() + lineStartOffset, nextOffset - lineStartOffset, character);
return lineStartOffset + offset;
}
std::size_t LuaSource::GetTotalLine() const {
return _linenumber;
}
void LuaSource::PushLine(std::size_t offset) {
_lineOffsetVec.push_back(offset);
_linenumber++;
}
std::string_view LuaSource::GetSource() const {
return _source;
}
std::string_view LuaSource::Slice(std::size_t startOffset, std::size_t endOffset) const {
std::string_view source = _source;
return source.substr(startOffset, endOffset - startOffset + 1);
}
std::string_view LuaSource::Slice(TextRange range) const {
if (range.Length == 0) {
return "";
}
return Slice(range.StartOffset, range.GetEndOffset());
}
void LuaSource::SetTotalLine(std::size_t line) {
_linenumber = line;
}
void LuaSource::UpdateLineInfo(std::size_t startLine) {
auto totalLine = GetTotalLine();
std::size_t startOffset = 0;
if (totalLine < startLine) {
startLine = 0;
} else {
startOffset = _lineOffsetVec[startLine];
}
_lineOffsetVec.resize(startLine + 1);
for (; startOffset < _source.size(); startOffset++) {
if (_source[startOffset] == '\n') {
_lineOffsetVec.push_back(startOffset + 1);
}
}
}
void LuaSource::Reset() {
_lineOffsetVec.resize(0);
_lineOffsetVec.push_back(0);
_linenumber = 0;
_lineState = EndOfLine::UNKNOWN;
}
void LuaSource::SetEndOfLineState(EndOfLine endOfLine) {
switch (_lineState) {
case EndOfLine::UNKNOWN: {
_lineState = endOfLine;
break;
}
case EndOfLine::CR:
case EndOfLine::LF:
case EndOfLine::CRLF: {
if (_lineState != endOfLine) {
_lineState = EndOfLine::MIX;
}
break;
}
default: {
break;
}
}
}
EndOfLine LuaSource::GetEndOfLine() const {
return _lineState;
}
std::size_t LuaSource::GetLineRestCharacter(std::size_t offset) {
auto line = GetLine(offset);
std::size_t bytesLength = 0;
if (line + 1 < _lineOffsetVec.size()) {
auto nextOffset = _lineOffsetVec[line + 1];
bytesLength = nextOffset - offset;
} else {
bytesLength = _source.size() - 1 - offset;
}
if (bytesLength > 0) {
return utf8::Utf8nLen(_source.data() + offset, bytesLength);
} else {
return 0;
}
}
TextRange LuaSource::GetIndentRange(std::size_t offset) const {
std::string_view source = GetSource();
auto line = GetLine(offset);
const auto start = GetOffset(line, 0);
auto index = start;
for (; index < offset; index++) {
auto ch = source[index];
if (ch != '\t' && ch != ' ') {
return TextRange(start, index - start);
}
}
return TextRange(start, index - start);
}
bool LuaSource::IsEmptyLine(std::size_t line) const {
if (line >= _lineOffsetVec.size()) {
return true;
}
std::size_t lineStartOffset = _lineOffsetVec[line];
std::size_t nextLineStartOffset = 0;
if (line + 1 == _lineOffsetVec.size()) {
nextLineStartOffset = _source.size();
} else {
nextLineStartOffset = _lineOffsetVec[line + 1];
}
for (auto offset = lineStartOffset; offset < nextLineStartOffset; offset++) {
char ch = _source[offset];
if (ch != '\n' && ch != '\r' && ch != '\t' && ch != ' ') {
return false;
}
}
return true;
}