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 : #include <algorithm>
6 : #include <fstream>
7 : #include <iostream>
8 : #include <string>
9 :
10 : #include "src/base/logging.h"
11 : #include "src/torque/ast.h"
12 : #include "src/torque/utils.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 : namespace torque {
17 :
18 367 : std::string StringLiteralUnquote(const std::string& s) {
19 : DCHECK(('"' == s.front() && '"' == s.back()) ||
20 : ('\'' == s.front() && '\'' == s.back()));
21 734 : std::stringstream result;
22 11287 : for (size_t i = 1; i < s.length() - 1; ++i) {
23 5460 : if (s[i] == '\\') {
24 0 : switch (s[++i]) {
25 : case 'n':
26 : result << '\n';
27 : break;
28 : case 'r':
29 : result << '\r';
30 : break;
31 : case 't':
32 : result << '\t';
33 : break;
34 : case '\'':
35 : case '"':
36 : case '\\':
37 : result << s[i];
38 : break;
39 : default:
40 0 : UNREACHABLE();
41 : }
42 : } else {
43 : result << s[i];
44 : }
45 : }
46 367 : return result.str();
47 : }
48 :
49 1735 : std::string StringLiteralQuote(const std::string& s) {
50 3470 : std::stringstream result;
51 : result << '"';
52 115959 : for (size_t i = 0; i < s.length(); ++i) {
53 57112 : switch (s[i]) {
54 : case '\n':
55 0 : result << "\\n";
56 : break;
57 : case '\r':
58 0 : result << "\\r";
59 : break;
60 : case '\t':
61 0 : result << "\\t";
62 : break;
63 : case '\'':
64 : case '"':
65 : case '\\':
66 : result << "\\" << s[i];
67 : break;
68 : default:
69 : result << s[i];
70 : }
71 : }
72 : result << '"';
73 1735 : return result.str();
74 : }
75 :
76 : static const char kFileUriPrefix[] = "file://";
77 : static const int kFileUriPrefixLength = sizeof(kFileUriPrefix) - 1;
78 :
79 4 : static int HexCharToInt(unsigned char c) {
80 4 : if (isdigit(c)) return c - '0';
81 2 : if (isupper(c)) return c - 'A' + 10;
82 : DCHECK(islower(c));
83 1 : return c - 'a' + 10;
84 : }
85 :
86 7 : base::Optional<std::string> FileUriDecode(const std::string& uri) {
87 : // Abort decoding of URIs that don't start with "file://".
88 7 : if (uri.rfind(kFileUriPrefix) != 0) return base::nullopt;
89 :
90 6 : const std::string path = uri.substr(kFileUriPrefixLength);
91 12 : std::ostringstream decoded;
92 :
93 103 : for (auto iter = path.begin(), end = path.end(); iter != end; ++iter) {
94 100 : std::string::value_type c = (*iter);
95 :
96 : // Normal characters are appended.
97 100 : if (c != '%') {
98 : decoded << c;
99 : continue;
100 : }
101 :
102 : // If '%' is not followed by at least two hex digits, we abort.
103 5 : if (std::distance(iter, end) <= 2) return base::nullopt;
104 :
105 3 : unsigned char first = (*++iter);
106 3 : unsigned char second = (*++iter);
107 3 : if (!isxdigit(first) || !isxdigit(second)) return base::nullopt;
108 :
109 : // An escaped hex value needs converting.
110 2 : unsigned char value = HexCharToInt(first) * 16 + HexCharToInt(second);
111 : decoded << value;
112 : }
113 :
114 3 : return decoded.str();
115 : }
116 :
117 0 : std::string CurrentPositionAsString() {
118 0 : return PositionAsString(CurrentSourcePosition::Get());
119 : }
120 :
121 12 : DEFINE_CONTEXTUAL_VARIABLE(LintErrorStatus)
122 :
123 2 : [[noreturn]] void ThrowTorqueError(const std::string& message,
124 : bool include_position) {
125 4 : TorqueError error(message);
126 2 : if (include_position) error.position = CurrentSourcePosition::Get();
127 4 : throw error;
128 : }
129 :
130 0 : void LintError(const std::string& error) {
131 : LintErrorStatus::SetLintError();
132 0 : std::cerr << CurrentPositionAsString() << ": Lint error: " << error << "\n";
133 0 : }
134 :
135 0 : void NamingConventionError(const std::string& type, const std::string& name,
136 : const std::string& convention) {
137 0 : std::stringstream sstream;
138 : sstream << type << " \"" << name << "\" doesn't follow \"" << convention
139 0 : << "\" naming convention.";
140 0 : LintError(sstream.str());
141 0 : }
142 :
143 : namespace {
144 :
145 : bool ContainsUnderscore(const std::string& s) {
146 3754 : if (s.empty()) return false;
147 3754 : return s.find("_") != std::string::npos;
148 : }
149 :
150 50 : bool ContainsUpperCase(const std::string& s) {
151 50 : if (s.empty()) return false;
152 579 : return std::any_of(s.begin(), s.end(), [](char c) { return isupper(c); });
153 : }
154 :
155 : // Torque has some namespace constants that are used like language level
156 : // keywords, e.g.: 'True', 'Undefined', etc.
157 : // These do not need to follow the default naming convention for constants.
158 : bool IsKeywordLikeName(const std::string& s) {
159 : static const char* const keyword_like_constants[]{"True", "False", "Hole",
160 : "Null", "Undefined"};
161 :
162 : return std::find(std::begin(keyword_like_constants),
163 : std::end(keyword_like_constants),
164 : s) != std::end(keyword_like_constants);
165 : }
166 :
167 : // Untagged/MachineTypes like 'int32', 'intptr' etc. follow a 'all-lowercase'
168 : // naming convention and are those exempt from the normal type convention.
169 : bool IsMachineType(const std::string& s) {
170 : static const char* const machine_types[]{
171 : "void", "never", "int8", "uint8", "int16", "uint16",
172 : "int31", "uint31", "int32", "uint32", "int64", "intptr",
173 : "uintptr", "float32", "float64", "bool", "string", "bint"};
174 :
175 : return std::find(std::begin(machine_types), std::end(machine_types), s) !=
176 : std::end(machine_types);
177 : }
178 :
179 : } // namespace
180 :
181 2712 : bool IsLowerCamelCase(const std::string& s) {
182 2712 : if (s.empty()) return false;
183 5424 : return islower(s[0]) && !ContainsUnderscore(s);
184 : }
185 :
186 1042 : bool IsUpperCamelCase(const std::string& s) {
187 1042 : if (s.empty()) return false;
188 2084 : return isupper(s[0]) && !ContainsUnderscore(s);
189 : }
190 :
191 50 : bool IsSnakeCase(const std::string& s) {
192 50 : if (s.empty()) return false;
193 50 : return !ContainsUpperCase(s);
194 : }
195 :
196 33 : bool IsValidNamespaceConstName(const std::string& s) {
197 33 : if (s.empty()) return false;
198 33 : if (IsKeywordLikeName(s)) return true;
199 :
200 56 : return s[0] == 'k' && IsUpperCamelCase(s.substr(1));
201 : }
202 :
203 215 : bool IsValidTypeName(const std::string& s) {
204 215 : if (s.empty()) return false;
205 215 : if (IsMachineType(s)) return true;
206 :
207 193 : return IsUpperCamelCase(s);
208 : }
209 :
210 119 : std::string CapifyStringWithUnderscores(const std::string& camellified_string) {
211 : std::string result;
212 : bool previousWasLower = false;
213 1851 : for (auto current : camellified_string) {
214 1732 : if (previousWasLower && isupper(current)) {
215 : result += "_";
216 : }
217 1732 : result += toupper(current);
218 1732 : previousWasLower = (islower(current));
219 : }
220 119 : return result;
221 : }
222 :
223 5496 : std::string CamelifyString(const std::string& underscore_string) {
224 : std::string result;
225 : bool word_beginning = true;
226 42264 : for (auto current : underscore_string) {
227 36768 : if (current == '_' || current == '-') {
228 : word_beginning = true;
229 : continue;
230 : }
231 35307 : if (word_beginning) {
232 6957 : current = toupper(current);
233 : }
234 : result += current;
235 : word_beginning = false;
236 : }
237 5496 : return result;
238 : }
239 :
240 1808 : std::string DashifyString(const std::string& underscore_string) {
241 : std::string result = underscore_string;
242 : std::replace(result.begin(), result.end(), '_', '-');
243 1808 : return result;
244 : }
245 :
246 87 : void ReplaceFileContentsIfDifferent(const std::string& file_path,
247 : const std::string& contents) {
248 174 : std::ifstream old_contents_stream(file_path.c_str());
249 : std::string old_contents;
250 87 : if (old_contents_stream.good()) {
251 : std::istreambuf_iterator<char> eos;
252 0 : old_contents =
253 : std::string(std::istreambuf_iterator<char>(old_contents_stream), eos);
254 0 : old_contents_stream.close();
255 : }
256 87 : if (old_contents.length() == 0 || old_contents != contents) {
257 174 : std::ofstream new_contents_stream;
258 87 : new_contents_stream.open(file_path.c_str());
259 : new_contents_stream << contents;
260 87 : new_contents_stream.close();
261 : }
262 87 : }
263 :
264 : } // namespace torque
265 : } // namespace internal
266 59456 : } // namespace v8
|