#include #include #include #include #include #include namespace willowc { std::optional SourceManager::addFile(std::string_view _path) { std::error_code ec; std::filesystem::path uncanonical_path{_path}; auto path = std::filesystem::weakly_canonical(uncanonical_path, ec); if (ec) { return std::nullopt; } std::filesystem::path display_path = path; display_path.make_preferred(); std::string display = display_path.string(); assert(!getFileID(display)); if (!std::filesystem::exists(path, ec) || ec) return std::nullopt; if (!std::filesystem::is_regular_file(path, ec) || ec) return std::nullopt; std::size_t filesize = std::filesystem::file_size(path, ec); if (ec) return std::nullopt; std::ifstream f{display_path, std::ios::binary}; if (!f) return std::nullopt; auto buf = std::make_unique(filesize); f.read(buf.get(), filesize); const FileID id = file_table.size(); file_table.emplace_back(std::move(display), std::string(_path), std::move(buf), filesize); ids[file_table.back().path] = id; return id; } std::optional SourceManager::getFileID(const std::string &path) { auto it = ids.find(path); if (it != ids.end()) return it->second; return std::nullopt; } std::optional SourceManager::addStdIn() { std::string content{std::istreambuf_iterator(std::cin), std::istreambuf_iterator()}; if (std::cin.bad()) return std::nullopt; std::size_t size = content.size(); auto buf = std::make_unique(size); const FileID id = file_table.size(); file_table.emplace_back("", "", std::move(buf), size); ids[file_table.back().path] = id; return id; } willow::Location SourceManager::File::getLoc(std::size_t offset) { size_t line_start = offset; while (line_start != 0) { if (this->buf[--line_start] != '\n') continue; line_start++; break; } uint32_t col = offset - line_start + 1; auto it = linecache_.find(line_start); if (it != linecache_.end()) return willow::Location{display_path, it->second, col, offset}; auto back = linecache_.rbegin(); auto i = back->first; auto line = back->second; assert(i < line_start); for (; i < line_start; i++) { if (buf[i] == '\n') { line = line + 1; size_t next_start = i + 1; if (next_start <= size) linecache_.insert({next_start, ++line}); } } linecache_.insert({line_start, line}); return willow::Location{ display_path, line, static_cast(offset - line_start + 1), offset}; } } // namespace willowc