-
Notifications
You must be signed in to change notification settings - Fork 515
/
Loc.h
151 lines (125 loc) · 4.96 KB
/
Loc.h
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
#ifndef SORBET_AST_LOC_H
#define SORBET_AST_LOC_H
#include "core/Files.h"
#include "core/LocOffsets.h"
namespace sorbet::core {
namespace serialize {
class SerializerImpl;
}
class GlobalState;
class Context;
class MutableContext;
class Loc final {
struct {
LocOffsets offsets;
core::FileRef fileRef;
} storage;
template <typename H> friend H AbslHashValue(H h, const Loc &m);
friend class sorbet::core::serialize::SerializerImpl;
void setFile(core::FileRef file) {
storage.fileRef = file;
}
public:
static Loc none(FileRef file = FileRef()) {
return Loc{file, LocOffsets::none()};
}
bool exists() const {
return storage.fileRef != 0 && storage.offsets.exists();
}
bool empty() const {
ENFORCE_NO_TIMER(exists());
return storage.offsets.empty();
}
Loc join(Loc other) const;
// For a given Loc, returns a zero-length version that starts at the same location.
Loc copyWithZeroLength() const {
return {this->storage.fileRef, this->storage.offsets.copyWithZeroLength()};
}
// As above, but returns a zero-length version that starts at the end of the Loc.
Loc copyEndWithZeroLength() const {
return {this->storage.fileRef, this->storage.offsets.copyEndWithZeroLength()};
}
uint32_t beginPos() const {
return storage.offsets.beginLoc;
};
uint32_t endPos() const {
return storage.offsets.endLoc;
}
const LocOffsets &offsets() const {
return storage.offsets;
}
FileRef file() const {
return storage.fileRef;
}
bool isTombStoned(const GlobalState &gs) const {
auto f = file();
if (!f.exists()) {
return false;
} else {
return file().data(gs).sourceType == File::Type::TombStone;
}
}
inline Loc(FileRef file, uint32_t begin, uint32_t end) : storage{{begin, end}, file} {
ENFORCE_NO_TIMER(begin <= INVALID_POS_LOC);
ENFORCE_NO_TIMER(end <= INVALID_POS_LOC);
ENFORCE_NO_TIMER(begin <= end);
}
inline Loc(FileRef file, LocOffsets offsets) : Loc(file, offsets.beginPos(), offsets.endPos()){};
Loc() : Loc(0, LocOffsets::none()){};
Loc &operator=(const Loc &rhs) = default;
Loc &operator=(Loc &&rhs) = default;
Loc(const Loc &rhs) = default;
Loc(Loc &&rhs) = default;
struct Detail {
// 1-indexed, like would be reported in a text editor (useful for error messages)
uint32_t line, column;
};
bool contains(const Loc &other) const;
std::pair<Detail, Detail> position(const GlobalState &gs) const;
std::string toStringWithTabs(const GlobalState &gs, int tabs = 0) const;
std::string toString(const GlobalState &gs) const {
return toStringWithTabs(gs);
}
std::string showRaw(const GlobalState &gs) const;
std::string filePosToString(const GlobalState &gs, bool showFull = false) const;
std::optional<std::string_view> source(const GlobalState &gs) const;
bool operator==(const Loc &rhs) const;
bool operator!=(const Loc &rhs) const;
static std::optional<uint32_t> pos2Offset(const File &file, Detail pos);
static Detail offset2Pos(const File &file, uint32_t off);
static std::optional<Loc> fromDetails(const GlobalState &gs, FileRef fileRef, Detail begin, Detail end);
// Create a new Loc by adjusting the beginPos and endPos of this Loc, like this:
//
// Loc{file(), beginPos() + beginAdjust, endPos() + endAdjust}
//
// but takes care to check that the resulting Loc is a valid slice of the source() buffer,
// taking care to avoid integer overflow / underflow.
//
// For example:
//
// `loc.adjust(gs, -1, 0).exists() == false` if `loc.beginPos() == 0`
// `loc.adjust(gs, 0, 1).exists() == false` if `loc.endPos() == loc.file().data(gs).source().size()`
//
// etc.
Loc adjust(const GlobalState &gs, int32_t beginAdjust, int32_t endAdjust) const;
// Like `Loc::adjust`, but takes a start offset and length, instead of independently adjusting
// the begin and end positions.
Loc adjustLen(const GlobalState &gs, int32_t beginAdjust, int32_t len) const;
// For a given Loc, returns
//
// - the Loc corresponding to the first non-whitespace character on this line, and
// - how many characters of the start of this line are whitespace.
//
std::pair<Loc, uint32_t> findStartOfLine(const GlobalState &gs) const;
// If the given loc spans multiple lines, return a new location which has been truncated to
// one line (excluding the newline character which ends the first line).
//
// Otherwise, return the current loc unchanged.
Loc truncateToFirstLine(const GlobalState &gs) const;
};
CheckSize(Loc, 12, 4);
template <typename H> H AbslHashValue(H h, const Loc &m) {
return H::combine(std::move(h), m.storage.offsets.beginLoc, m.storage.offsets.endLoc, m.storage.fileRef.id());
}
} // namespace sorbet::core
#endif // SORBET_AST_LOC_H