1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
#pragma once
/**
* @file
*
* @brief Pos and AbstractPos
*/
#include <cstdint>
#include <string>
#include <variant>
#include "lix/libutil/source-path.hh"
namespace nix {
/**
* A position and an origin for that position (like a source file).
*/
struct Pos
{
uint32_t line = 0;
uint32_t column = 0;
struct Stdin {
ref<std::string> source;
constexpr friend auto operator<=>(Stdin const & lhs, Stdin const & rhs)
{
return *lhs.source <=> *rhs.source;
}
};
struct String {
ref<std::string> source;
constexpr friend auto operator<=>(String const & lhs, String const & rhs)
{
return *lhs.source <=> *rhs.source;
}
};
struct Hidden {
auto operator<=>(const Hidden &) const = default;
};
struct Origin : std::variant<std::monostate, Stdin, String, CheckedSourcePath, Hidden>
{
using variant = variant;
// Forward all construction to std::variant.
template<typename... Args>
constexpr Origin(Args &&... rhs) noexcept(noexcept(variant(std::forward<Args>(rhs)...)))
: variant(std::forward<Args>(rhs)...)
{
}
std::optional<std::string> getSource() const;
constexpr friend bool operator==(Origin const & lhs, Origin const & rhs)
{
// clang-format: off
return std::visit(overloaded {
[&](std::monostate const &, std::monostate const &) {
return true;
},
[&](Stdin const & lStdin, Stdin const & rStdin) {
// NOTE: comparing the `ref<>`s, not their contents.
return lStdin.source == rStdin.source;
},
[&](String const & lStr, String const & rStr) {
// NOTE: comparing the `ref<>`s, not their contents.
return lStr.source == rStr.source;
},
[&](CheckedSourcePath const & lPath, CheckedSourcePath const & rPath) {
return lPath == rPath;
},
[](Hidden const & lHidden, Hidden const & rHidden) {
// NOTE(Qyriad): Pos::Hidden is an empty class with a default `operator==`,
// so we believe this will always be true. We forward the comparison anyway
// 1) because we could be wrong, and 2) so if `Hidden`'s behavior changes
// this part doesn't accidentally become incorrect.
return lHidden == rHidden;
},
[](auto const &, auto const &) {
// This means lhs and rhs were different types, in which case we never
// consider them equal.
return false;
},
}, lhs, rhs);
// clang-format: on
}
};
Origin origin = std::monostate();
Pos() { }
Pos(uint32_t line, uint32_t column, Origin origin)
: line(line), column(column), origin(origin) { }
Pos(Pos & other) = default;
Pos(const Pos & other) = default;
Pos(Pos && other) = default;
Pos(const Pos * other);
explicit operator bool() const { return line > 0; }
operator std::shared_ptr<Pos>() const;
/**
* Return the contents of the source file.
*/
std::optional<std::string> getSource() const;
void print(std::ostream & out, bool showOrigin) const;
std::optional<LinesOfCode> getCodeLines() const;
// Not defaulted because it's implicitly deleted because C++ is stupid.
constexpr friend auto operator<=>(Pos const & lhs, Pos const & rhs)
{
return std::forward_as_tuple(lhs.line, lhs.column, lhs.origin)
<=> std::forward_as_tuple(rhs.line, rhs.column, rhs.origin);
}
// operator<=> doesn't generate this because it's not defaulted.
constexpr friend bool operator==(Pos const & lhs, Pos const & rhs) = default;
struct LinesIterator {
using difference_type = size_t;
using value_type = std::string_view;
using reference = const std::string_view &;
using pointer = const std::string_view *;
using iterator_category = std::input_iterator_tag;
LinesIterator(): pastEnd(true) {}
explicit LinesIterator(std::string_view input): input(input), pastEnd(input.empty()) {
if (!pastEnd)
bump(true);
}
LinesIterator & operator++() {
bump(false);
return *this;
}
LinesIterator operator++(int) {
auto result = *this;
++*this;
return result;
}
reference operator*() const { return curLine; }
pointer operator->() const { return &curLine; }
bool operator!=(const LinesIterator & other) const {
return !(*this == other);
}
bool operator==(const LinesIterator & other) const {
return (pastEnd && other.pastEnd)
|| (std::forward_as_tuple(input.size(), input.data())
== std::forward_as_tuple(other.input.size(), other.input.data()));
}
private:
std::string_view input, curLine;
bool pastEnd = false;
void bump(bool atFirst);
};
};
std::ostream & operator<<(std::ostream & str, const Pos & pos);
}
|