FE 0.15.0
A C++23 toolkit for writing compiler/interpreter frontends.
Loading...
Searching...
No Matches
src.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4
5#include <filesystem>
6#include <iosfwd>
7#include <string>
8#include <string_view>
9#include <utility>
10#include <vector>
11
12#ifdef FE_ABSL
13# include <absl/container/node_hash_map.h>
14#else
15# include <unordered_map>
16#endif
17
18#include "fe/loc.h"
19
20namespace fe {
21
22/// Hashes a `std::filesystem::path` - consistent with its `operator==`, which compares lexically.
23struct PathHash {
24 size_t operator()(const std::filesystem::path& path) const noexcept { return std::filesystem::hash_value(path); }
25};
26
27/// Maps a `std::filesystem::path` to @p V.
28/// @warning Node-based on purpose: fe::SrcMap stores its Src%s in here and a Loc points to one,
29/// so the values must never move.
30#ifdef FE_ABSL
31template<class V>
32using PathMap = absl::node_hash_map<std::filesystem::path, V, PathHash>;
33#else
34template<class V>
35using PathMap = std::unordered_map<std::filesystem::path, V, PathHash>;
36#endif
37
38/// The content of one source file together with the offsets its rows start at.
39/// This is what turns a Pos back into the row/column a human wants to read.
40class Src {
41public:
42 Src(std::filesystem::path path, std::string buf);
43
44 /// @name Getters
45 ///@{
46 const std::filesystem::path& path() const { return path_; }
47 std::string_view buf() const { return buf_; }
48 /// The number of rows the file actually has.
49 /// @note A trailing line terminator does *not* open one more, empty row - it ends the last one.
50 uint32_t num_rows() const;
51 Pos begin() const { return Pos(0); }
52 Pos end() const { return Pos((uint32_t)buf_.size()); }
53 bool contains(Pos pos) const { return pos && pos.off <= buf_.size(); }
54 ///@}
55
56 /// @name Resolve a Pos
57 ///@{
58 /// 1-based row and column @p pos sits at, or `{0, 0}` if @p pos does not belong to this file.
59 /// The column counts code points, not bytes, and a leading utf8::Bom occupies none.
60 /// @note Never names a row Src::num_rows does not count - see there.
61 std::pair<uint32_t, uint32_t> rowcol(Pos pos) const;
62
63 uint32_t row(Pos pos) const { return rowcol(pos).first; }
64 uint32_t col(Pos pos) const { return rowcol(pos).second; }
65
66 /// Text of the 1-based @p row without its line terminator - or a leading utf8::Bom;
67 /// empty if @p row is out of range.
68 std::string_view line(uint32_t row) const;
69
70 /// Start of the last code point before @p pos - the character a half-open Loc::end points *past*.
71 Pos prev(Pos pos) const;
72 ///@}
73
74private:
75 /// Scanning for `\n` appends one more offset when buf_ ends with a terminator: a row with
76 /// nothing in it and nothing after it. A terminator *ends* its row rather than opening a new
77 /// one, so that entry is an artifact of the scan and not a row the file has.
78 uint32_t phantom_() const { return rows_.size() > 1 && rows_.back() == buf_.size() ? 1 : 0; }
79
80 std::string_view sub(uint32_t begin, uint32_t end) const {
81 return std::string_view(buf_).substr(begin, end - begin);
82 }
83
84 std::filesystem::path path_;
85 std::string buf_;
86 std::vector<uint32_t> rows_; ///< Offset each row starts at; `rows_.front() == 0`.
87 uint32_t bom_ = 0; ///< Byte size of a leading utf8::Bom, which is not a column.
88};
89
90/// Interns the text - and the `std::filesystem::path` - of every file a Loc may point into.
91/// Keep one in your Driver: a Loc is only as good as the SrcMap that keeps its Src alive.
92/// Each file lives here exactly once, so Loc::src identifies it by pointer - see SrcMap::key.
93class SrcMap {
94public:
95 /// @name Register a File
96 ///@{
97 /// Registers @p path with @p buf as its content and reports whether it is fresh.
98 /// A @p path with the same SrcMap::key as an already registered one yields that entry instead.
99 std::pair<const Src*, bool> add(std::filesystem::path path, std::string buf);
100
101 /// As above, but reads the content from @p path.
102 /// @returns a `nullptr` Src if @p path cannot be opened.
103 std::pair<const Src*, bool> add(std::filesystem::path path);
104
105 /// Reads all of @p is into a `std::string`.
106 static std::string slurp(std::istream& is);
107 ///@}
108
109 /// @name Lookup
110 ///@{
111 /// @returns `nullptr` if @p path has not been registered.
112 /// @note Compares SrcMap::key%s, so a @p path that merely *spells* a registered file
113 /// differently still finds it.
114 const Src* lookup(const std::filesystem::path& path) const;
115
116 /// The key @p path is interned under - absolute, symlink-free, and normalized.
117 /// This is where "do these two paths name the same file?" is decided - once, upon SrcMap::add -
118 /// so that every comparison afterwards is a plain Loc::src pointer comparison.
119 /// @note Resolves symlinks and `.`/`..` as far as @p path exists on disk and normalizes the rest
120 /// lexically. A relative @p path is resolved against the current working directory *now*.
121 static std::filesystem::path key(const std::filesystem::path& path);
122 ///@}
123
124private:
125 PathMap<Src> path2src_; ///< Keyed by SrcMap::key; node-based, so a Src never moves.
126};
127
128} // namespace fe
Interns the text - and the std::filesystem::path - of every file a Loc may point into.
Definition src.h:93
std::pair< const Src *, bool > add(std::filesystem::path path)
As above, but reads the content from path.
static std::filesystem::path key(const std::filesystem::path &path)
The key path is interned under - absolute, symlink-free, and normalized.
const Src * lookup(const std::filesystem::path &path) const
std::pair< const Src *, bool > add(std::filesystem::path path, std::string buf)
static std::string slurp(std::istream &is)
Reads all of is into a std::string.
The content of one source file together with the offsets its rows start at.
Definition src.h:40
std::string_view buf() const
Definition src.h:47
Pos begin() const
Definition src.h:51
std::string_view line(uint32_t row) const
Text of the 1-based row without its line terminator - or a leading utf8::Bom; empty if row is out of ...
uint32_t num_rows() const
The number of rows the file actually has.
Pos end() const
Definition src.h:52
bool contains(Pos pos) const
Definition src.h:53
uint32_t col(Pos pos) const
Definition src.h:64
Src(std::filesystem::path path, std::string buf)
const std::filesystem::path & path() const
Definition src.h:46
Pos prev(Pos pos) const
Start of the last code point before pos - the character a half-open Loc::end points past.
uint32_t row(Pos pos) const
Definition src.h:63
std::pair< uint32_t, uint32_t > rowcol(Pos pos) const
Definition algo.h:17
std::unordered_map< std::filesystem::path, V, PathHash > PathMap
Maps a std::filesystem::path to V.
Definition src.h:35
Hashes a std::filesystem::path - consistent with its operator==, which compares lexically.
Definition src.h:23
size_t operator()(const std::filesystem::path &path) const noexcept
Definition src.h:24
Byte offset into a Src; pass around as value.
Definition loc.h:16
uint32_t off
Definition loc.h:31
constexpr Pos() noexcept=default
Creates an invalid Position.