Files
Fig/src/SourceManager/SourceManager.hpp

146 lines
3.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*!
@file src/SourceManager/SourceManager.hpp
@brief 源代码管理
@author PuqiAR (im@puqiar.top)
@date 2026-02-14
*/
#pragma once
#include <Core/SourceLocations.hpp>
#include <Deps/Deps.hpp>
#include <fstream>
namespace Fig
{
class SourceManager
{
private:
String filePath;
String source;
std::vector<String> lines;
std::vector<size_t> lineStartIndex; // 每行在整个源字符串中的起始 index
void preprocessLineIndices()
{
lineStartIndex.clear();
lineStartIndex.push_back(0);
for (size_t i = 0; i < source.length(); ++i)
{
if (source[i] == U'\n')
{
lineStartIndex.push_back(i + 1);
}
else if (source[i] == U'\r')
{
// 处理 CRLF只在 \n 处记录
if (i + 1 < source.length() && source[i + 1] == U'\n')
continue;
lineStartIndex.push_back(i + 1);
}
}
}
public:
bool read = false;
String &Read()
{
std::fstream fs(filePath.toStdString());
if (!fs.is_open())
{
read = false;
return source;
}
std::string line;
while (std::getline(fs, line))
{
source += line + '\n';
lines.push_back(String(line));
}
if (!source.empty() && source.back() == U'\n')
source.pop_back();
if (lines.empty())
{
lines.push_back(String()); // 填充一个空的
}
read = true;
preprocessLineIndices();
return source;
}
SourceManager() {}
SourceManager(String _path)
{
filePath = std::move(_path);
}
bool HasLine(int64_t _line) const
{
return _line <= lines.size() && _line >= 1;
}
const String &GetLine(size_t _line) const
{
assert(_line <= lines.size() && "SourceManager: GetLine failed, index out of range");
return lines[_line - 1];
}
String GetSub(size_t _index_start, size_t _length) const
{
return source.substr(_index_start, _length);
}
const String &GetSource() const
{
return source;
}
String &GetSource()
{
return source;
}
std::pair<size_t, size_t> GetLineColumn(size_t index) const
{
if (lineStartIndex.empty())
{
return {1, 1};
}
// clamp index 到合法范围Parser报错可能传入EOF位置
// size_t lastLine = lineStartIndex.size() - 1;
if (index < lineStartIndex[0])
{
return {1, 1};
}
// upper_bound 找到第一个 > index 的行起点
auto it = std::ranges::upper_bound(lineStartIndex.begin(), lineStartIndex.end(), index);
size_t line;
if (it == lineStartIndex.begin())
{
line = 0;
}
else
{
line = static_cast<size_t>(it - lineStartIndex.begin() - 1);
}
size_t column = index - lineStartIndex[line] + 1;
return {line + 1, column};
}
void LoadFromMemory(String src)
{
source = std::move(src);
read = true;
preprocessLineIndices();
}
};
}; // namespace Fig