Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/mono/utils/naming_utils.cpp
10279 views
1
/**************************************************************************/
2
/* naming_utils.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "naming_utils.h"
32
33
#include "core/string/ucaps.h"
34
#include "core/templates/hash_map.h"
35
36
HashMap<String, String> _create_hashmap_from_vector(Vector<Pair<String, String>> vector) {
37
HashMap<String, String> hashmap = HashMap<String, String>(vector.size());
38
for (const Pair<String, String> &pair : vector) {
39
hashmap.insert(pair.first, pair.second);
40
}
41
return hashmap;
42
}
43
44
// Hardcoded collection of PascalCase name conversions.
45
const HashMap<String, String> pascal_case_name_overrides = _create_hashmap_from_vector({
46
{ "BitMap", "Bitmap" },
47
{ "JSONRPC", "JsonRpc" },
48
{ "Object", "GodotObject" },
49
{ "OpenXRIPBinding", "OpenXRIPBinding" },
50
{ "SkeletonModification2DCCDIK", "SkeletonModification2DCcdik" },
51
{ "SkeletonModification2DFABRIK", "SkeletonModification2DFabrik" },
52
{ "SkeletonModification3DCCDIK", "SkeletonModification3DCcdik" },
53
{ "SkeletonModification3DFABRIK", "SkeletonModification3DFabrik" },
54
{ "System", "System_" },
55
{ "Thread", "GodotThread" },
56
});
57
58
// Hardcoded collection of PascalCase part conversions.
59
const HashMap<String, String> pascal_case_part_overrides = _create_hashmap_from_vector({
60
{ "AA", "AA" }, // Anti Aliasing
61
{ "AO", "AO" }, // Ambient Occlusion
62
{ "FILENAME", "FileName" },
63
{ "FADEIN", "FadeIn" },
64
{ "FADEOUT", "FadeOut" },
65
{ "FX", "FX" },
66
{ "GI", "GI" }, // Global Illumination
67
{ "GZIP", "GZip" },
68
{ "HBOX", "HBox" }, // Horizontal Box
69
{ "ID", "Id" },
70
{ "IO", "IO" }, // Input/Output
71
{ "IP", "IP" }, // Internet Protocol
72
{ "IV", "IV" }, // Initialization Vector
73
{ "MACOS", "MacOS" },
74
{ "NODEPATH", "NodePath" },
75
{ "SPIRV", "SpirV" },
76
{ "STDIN", "StdIn" },
77
{ "STDOUT", "StdOut" },
78
{ "USERNAME", "UserName" },
79
{ "UV", "UV" },
80
{ "UV2", "UV2" },
81
{ "VBOX", "VBox" }, // Vertical Box
82
{ "WHITESPACE", "WhiteSpace" },
83
{ "WM", "WM" },
84
{ "XR", "XR" },
85
{ "XRAPI", "XRApi" },
86
});
87
88
String _get_pascal_case_part_override(String p_part, bool p_input_is_upper = true) {
89
if (!p_input_is_upper) {
90
for (int i = 0; i < p_part.length(); i++) {
91
p_part[i] = _find_upper(p_part[i]);
92
}
93
}
94
95
if (pascal_case_part_overrides.has(p_part)) {
96
return pascal_case_part_overrides.get(p_part);
97
}
98
99
return String();
100
}
101
102
Vector<String> _split_pascal_case(const String &p_identifier) {
103
Vector<String> parts;
104
int current_part_start = 0;
105
bool prev_was_upper = is_ascii_upper_case(p_identifier[0]);
106
for (int i = 1; i < p_identifier.length(); i++) {
107
if (prev_was_upper) {
108
if (is_digit(p_identifier[i]) || is_ascii_lower_case(p_identifier[i])) {
109
if (!is_digit(p_identifier[i])) {
110
// These conditions only apply when the separator is not a digit.
111
if (i - current_part_start == 1) {
112
// Upper character was only the beginning of a word.
113
prev_was_upper = false;
114
continue;
115
}
116
if (i != p_identifier.length()) {
117
// If this is not the last character, the last uppercase
118
// character is the start of the next word.
119
i--;
120
}
121
}
122
if (i - current_part_start > 0) {
123
parts.append(p_identifier.substr(current_part_start, i - current_part_start));
124
current_part_start = i;
125
prev_was_upper = false;
126
}
127
}
128
} else {
129
if (is_digit(p_identifier[i]) || is_ascii_upper_case(p_identifier[i])) {
130
parts.append(p_identifier.substr(current_part_start, i - current_part_start));
131
current_part_start = i;
132
prev_was_upper = true;
133
}
134
}
135
}
136
137
// Add the rest of the identifier as the last part.
138
if (current_part_start != p_identifier.length()) {
139
parts.append(p_identifier.substr(current_part_start));
140
}
141
142
return parts;
143
}
144
145
String pascal_to_pascal_case(const String &p_identifier) {
146
if (p_identifier.length() == 0) {
147
return p_identifier;
148
}
149
150
if (p_identifier.length() <= 2) {
151
return p_identifier.to_upper();
152
}
153
154
if (pascal_case_name_overrides.has(p_identifier)) {
155
// Use hardcoded value for the identifier.
156
return pascal_case_name_overrides.get(p_identifier);
157
}
158
159
Vector<String> parts = _split_pascal_case(p_identifier);
160
161
String ret;
162
163
for (String &part : parts) {
164
String part_override = _get_pascal_case_part_override(part);
165
if (!part_override.is_empty()) {
166
// Use hardcoded value for part.
167
ret += part_override;
168
continue;
169
}
170
171
if (part.length() <= 2 && part.to_upper() == part) {
172
// Acronym of length 1 or 2.
173
for (int j = 0; j < part.length(); j++) {
174
part[j] = _find_upper(part[j]);
175
}
176
ret += part;
177
continue;
178
}
179
180
part[0] = _find_upper(part[0]);
181
for (int i = 1; i < part.length(); i++) {
182
if (is_digit(part[i - 1])) {
183
// Use uppercase after digits.
184
part[i] = _find_upper(part[i]);
185
continue;
186
}
187
188
part[i] = _find_lower(part[i]);
189
}
190
ret += part;
191
}
192
193
return ret;
194
}
195
196
String snake_to_pascal_case(const String &p_identifier, bool p_input_is_upper) {
197
String ret;
198
Vector<String> parts = p_identifier.split("_", true);
199
200
for (int i = 0; i < parts.size(); i++) {
201
String part = parts[i];
202
203
String part_override = _get_pascal_case_part_override(part, p_input_is_upper);
204
if (!part_override.is_empty()) {
205
// Use hardcoded value for part.
206
ret += part_override;
207
continue;
208
}
209
210
if (!part.is_empty()) {
211
part[0] = _find_upper(part[0]);
212
for (int j = 1; j < part.length(); j++) {
213
if (is_digit(part[j - 1])) {
214
// Use uppercase after digits.
215
part[j] = _find_upper(part[j]);
216
continue;
217
}
218
219
if (p_input_is_upper) {
220
part[j] = _find_lower(part[j]);
221
}
222
}
223
ret += part;
224
} else {
225
if (i == 0 || i == (parts.size() - 1)) {
226
// Preserve underscores at the beginning and end
227
ret += "_";
228
} else {
229
// Preserve contiguous underscores
230
if (parts[i - 1].length()) {
231
ret += "__";
232
} else {
233
ret += "_";
234
}
235
}
236
}
237
}
238
239
return ret;
240
}
241
242
String snake_to_camel_case(const String &p_identifier, bool p_input_is_upper) {
243
String ret;
244
Vector<String> parts = p_identifier.split("_", true);
245
246
for (int i = 0; i < parts.size(); i++) {
247
String part = parts[i];
248
249
String part_override = _get_pascal_case_part_override(part, p_input_is_upper);
250
if (!part_override.is_empty()) {
251
// Use hardcoded value for part.
252
if (i == 0) {
253
part_override[0] = _find_lower(part_override[0]);
254
}
255
ret += part_override;
256
continue;
257
}
258
259
if (!part.is_empty()) {
260
if (i == 0) {
261
part[0] = _find_lower(part[0]);
262
} else {
263
part[0] = _find_upper(part[0]);
264
}
265
for (int j = 1; j < part.length(); j++) {
266
if (is_digit(part[j - 1])) {
267
// Use uppercase after digits.
268
part[j] = _find_upper(part[j]);
269
continue;
270
}
271
272
if (p_input_is_upper) {
273
part[j] = _find_lower(part[j]);
274
}
275
}
276
ret += part;
277
} else {
278
if (i == 0 || i == (parts.size() - 1)) {
279
// Preserve underscores at the beginning and end
280
ret += "_";
281
} else {
282
// Preserve contiguous underscores
283
if (parts[i - 1].length()) {
284
ret += "__";
285
} else {
286
ret += "_";
287
}
288
}
289
}
290
}
291
292
return ret;
293
}
294
295