Line data Source code
1 : // Copyright 2017 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_TORQUE_UTILS_H_
6 : #define V8_TORQUE_UTILS_H_
7 :
8 : #include <ostream>
9 : #include <streambuf>
10 : #include <string>
11 : #include <unordered_set>
12 : #include <vector>
13 :
14 : #include "src/base/functional.h"
15 : #include "src/base/optional.h"
16 : #include "src/torque/contextual.h"
17 : #include "src/torque/source-positions.h"
18 :
19 : namespace v8 {
20 : namespace internal {
21 : namespace torque {
22 :
23 : std::string StringLiteralUnquote(const std::string& s);
24 : std::string StringLiteralQuote(const std::string& s);
25 :
26 : // Decodes "file://" URIs into file paths which can then be used
27 : // with the standard stream API.
28 : V8_EXPORT_PRIVATE base::Optional<std::string> FileUriDecode(
29 : const std::string& s);
30 :
31 : class LintErrorStatus : public ContextualClass<LintErrorStatus> {
32 : public:
33 3 : LintErrorStatus() : has_lint_errors_(false) {}
34 :
35 3 : static bool HasLintErrors() { return Get().has_lint_errors_; }
36 0 : static void SetLintError() { Get().has_lint_errors_ = true; }
37 :
38 : private:
39 : bool has_lint_errors_;
40 : };
41 :
42 : void LintError(const std::string& error);
43 :
44 : // Prints a LintError with the format "{type} '{name}' doesn't follow
45 : // '{convention}' naming convention".
46 : void NamingConventionError(const std::string& type, const std::string& name,
47 : const std::string& convention);
48 :
49 : bool IsLowerCamelCase(const std::string& s);
50 : bool IsUpperCamelCase(const std::string& s);
51 : bool IsSnakeCase(const std::string& s);
52 : bool IsValidNamespaceConstName(const std::string& s);
53 : bool IsValidTypeName(const std::string& s);
54 :
55 22 : struct TorqueError : public std::exception {
56 6 : explicit TorqueError(const std::string& message) : message(message) {}
57 :
58 : std::string message;
59 : base::Optional<SourcePosition> position;
60 : };
61 :
62 : [[noreturn]] void ThrowTorqueError(const std::string& error,
63 : bool include_position);
64 : template <class... Args>
65 2 : [[noreturn]] void ReportError(Args&&... args) {
66 4 : std::stringstream s;
67 0 : USE((s << std::forward<Args>(args))...);
68 4 : ThrowTorqueError(s.str(), true);
69 : }
70 : template <class... Args>
71 0 : [[noreturn]] void ReportErrorWithoutPosition(Args&&... args) {
72 0 : std::stringstream s;
73 0 : USE((s << std::forward<Args>(args))...);
74 0 : ThrowTorqueError(s.str(), false);
75 : }
76 :
77 : std::string CapifyStringWithUnderscores(const std::string& camellified_string);
78 : std::string CamelifyString(const std::string& underscore_string);
79 : std::string DashifyString(const std::string& underscore_string);
80 :
81 : void ReplaceFileContentsIfDifferent(const std::string& file_path,
82 : const std::string& contents);
83 :
84 : std::string CurrentPositionAsString();
85 :
86 : template <class T>
87 9 : class Deduplicator {
88 : public:
89 : const T* Add(T x) { return &*(storage_.insert(std::move(x)).first); }
90 :
91 : private:
92 : std::unordered_set<T, base::hash<T>> storage_;
93 : };
94 :
95 : template <class C, class T>
96 7757 : void PrintCommaSeparatedList(std::ostream& os, const T& list, C transform) {
97 : bool first = true;
98 98503 : for (auto& e : list) {
99 45373 : if (first) {
100 : first = false;
101 : } else {
102 38080 : os << ", ";
103 : }
104 90746 : os << transform(e);
105 : }
106 7757 : }
107 :
108 : template <class T,
109 : typename std::enable_if<
110 : std::is_pointer<typename T::value_type>::value, int>::type = 0>
111 0 : void PrintCommaSeparatedList(std::ostream& os, const T& list) {
112 : bool first = true;
113 0 : for (auto& e : list) {
114 0 : if (first) {
115 : first = false;
116 : } else {
117 0 : os << ", ";
118 : }
119 0 : os << *e;
120 : }
121 0 : }
122 :
123 : template <class T,
124 : typename std::enable_if<
125 : !std::is_pointer<typename T::value_type>::value, int>::type = 0>
126 5579 : void PrintCommaSeparatedList(std::ostream& os, const T& list) {
127 : bool first = true;
128 15936 : for (auto& e : list) {
129 10357 : if (first) {
130 : first = false;
131 : } else {
132 4861 : os << ", ";
133 : }
134 363 : os << e;
135 : }
136 5579 : }
137 :
138 : struct BottomOffset {
139 : size_t offset;
140 : BottomOffset& operator++() {
141 15439 : ++offset;
142 : return *this;
143 : }
144 23302 : BottomOffset operator+(size_t x) const { return BottomOffset{offset + x}; }
145 : BottomOffset operator-(size_t x) const {
146 : DCHECK_LE(x, offset);
147 134148 : return BottomOffset{offset - x};
148 : }
149 : bool operator<(const BottomOffset& other) const {
150 : return offset < other.offset;
151 : }
152 : bool operator<=(const BottomOffset& other) const {
153 : return offset <= other.offset;
154 : }
155 : bool operator==(const BottomOffset& other) const {
156 204 : return offset == other.offset;
157 : }
158 : bool operator!=(const BottomOffset& other) const {
159 : return offset != other.offset;
160 : }
161 : };
162 :
163 : inline std::ostream& operator<<(std::ostream& out, BottomOffset from_bottom) {
164 : return out << "BottomOffset{" << from_bottom.offset << "}";
165 : }
166 :
167 : // An iterator-style range of stack slots.
168 : class StackRange {
169 : public:
170 57549 : StackRange(BottomOffset begin, BottomOffset end) : begin_(begin), end_(end) {
171 : DCHECK_LE(begin_, end_);
172 : }
173 :
174 : bool operator==(const StackRange& other) const {
175 204 : return begin_ == other.begin_ && end_ == other.end_;
176 : }
177 :
178 : void Extend(StackRange adjacent) {
179 : DCHECK_EQ(end_, adjacent.begin_);
180 7860 : end_ = adjacent.end_;
181 : }
182 :
183 143881 : size_t Size() const { return end_.offset - begin_.offset; }
184 : BottomOffset begin() const { return begin_; }
185 : BottomOffset end() const { return end_; }
186 :
187 : private:
188 : BottomOffset begin_;
189 : BottomOffset end_;
190 : };
191 :
192 : inline std::ostream& operator<<(std::ostream& out, StackRange range) {
193 : return out << "StackRange{" << range.begin() << ", " << range.end() << "}";
194 : }
195 :
196 : template <class T>
197 70828 : class Stack {
198 : public:
199 : using value_type = T;
200 : Stack() = default;
201 2 : Stack(std::initializer_list<T> initializer)
202 2 : : Stack(std::vector<T>(initializer)) {}
203 : explicit Stack(std::vector<T> v) : elements_(std::move(v)) {}
204 : size_t Size() const { return elements_.size(); }
205 : const T& Peek(BottomOffset from_bottom) const {
206 : return elements_.at(from_bottom.offset);
207 : }
208 1302 : void Poke(BottomOffset from_bottom, T x) {
209 1964 : elements_.at(from_bottom.offset) = std::move(x);
210 1302 : }
211 102977 : void Push(T x) { elements_.push_back(std::move(x)); }
212 : StackRange TopRange(size_t slot_count) const {
213 : DCHECK_GE(Size(), slot_count);
214 : return StackRange{AboveTop() - slot_count, AboveTop()};
215 : }
216 10171 : StackRange PushMany(const std::vector<T>& v) {
217 19422 : for (const T& x : v) {
218 9251 : Push(x);
219 : }
220 10171 : return TopRange(v.size());
221 : }
222 114446 : const T& Top() const { return Peek(AboveTop() - 1); }
223 4059 : T Pop() {
224 12184 : T result = std::move(elements_.back());
225 : elements_.pop_back();
226 4059 : return result;
227 : }
228 7475 : std::vector<T> PopMany(size_t count) {
229 : DCHECK_GE(elements_.size(), count);
230 : std::vector<T> result;
231 7475 : result.reserve(count);
232 16625 : for (auto it = elements_.end() - count; it != elements_.end(); ++it) {
233 : result.push_back(std::move(*it));
234 : }
235 7475 : elements_.resize(elements_.size() - count);
236 7475 : return result;
237 : }
238 : // The invalid offset above the top element. This is useful for StackRange.
239 : BottomOffset AboveTop() const { return BottomOffset{Size()}; }
240 : // Delete the slots in {range}, moving higher slots to fill the gap.
241 19834 : void DeleteRange(StackRange range) {
242 : DCHECK_LE(range.end(), AboveTop());
243 19834 : if (range.Size() == 0) return;
244 34956 : for (BottomOffset i = range.end(); i < AboveTop(); ++i) {
245 23334 : elements_[i.offset - range.Size()] = std::move(elements_[i.offset]);
246 : }
247 19517 : elements_.resize(elements_.size() - range.Size());
248 : }
249 :
250 : bool operator==(const Stack& other) const {
251 4710 : return elements_ == other.elements_;
252 : }
253 : bool operator!=(const Stack& other) const {
254 : return elements_ != other.elements_;
255 : }
256 :
257 : T* begin() { return elements_.data(); }
258 : T* end() { return begin() + elements_.size(); }
259 : const T* begin() const { return elements_.data(); }
260 : const T* end() const { return begin() + elements_.size(); }
261 :
262 : private:
263 : std::vector<T> elements_;
264 : };
265 :
266 : template <class T>
267 : T* CheckNotNull(T* x) {
268 : CHECK_NOT_NULL(x);
269 : return x;
270 : }
271 :
272 : template <class T>
273 : inline std::ostream& operator<<(std::ostream& os, Stack<T>& t) {
274 : os << "Stack{";
275 : PrintCommaSeparatedList(os, t);
276 : os << "}";
277 : return os;
278 : }
279 : class ToString {
280 : public:
281 : template <class T>
282 : ToString& operator<<(T&& x) {
283 : s_ << std::forward<T>(x);
284 : return *this;
285 : }
286 : operator std::string() { return s_.str(); }
287 :
288 : private:
289 : std::stringstream s_;
290 : };
291 :
292 : static const char* const kBaseNamespaceName = "base";
293 : static const char* const kTestNamespaceName = "test";
294 :
295 : // Erase elements of a container that has a constant-time erase function, like
296 : // std::set or std::list. Calling this on std::vector would have quadratic
297 : // complexity.
298 : template <class Container, class F>
299 121 : void EraseIf(Container* container, F f) {
300 303 : for (auto it = container->begin(); it != container->end();) {
301 364 : if (f(*it)) {
302 : it = container->erase(it);
303 : } else {
304 : ++it;
305 : }
306 : }
307 121 : }
308 :
309 9 : class NullStreambuf : public std::streambuf {
310 : public:
311 2724 : virtual int overflow(int c) {
312 2724 : setp(buffer_, buffer_ + sizeof(buffer_));
313 2724 : return (c == traits_type::eof()) ? '\0' : c;
314 : }
315 :
316 : private:
317 : char buffer_[64];
318 : };
319 :
320 6 : class NullOStream : public std::ostream {
321 : public:
322 12 : NullOStream() : std::ostream(&buffer_) {}
323 :
324 : private:
325 : NullStreambuf buffer_;
326 : };
327 :
328 : } // namespace torque
329 : } // namespace internal
330 : } // namespace v8
331 :
332 : #endif // V8_TORQUE_UTILS_H_
|