summaryrefslogtreecommitdiff
path: root/modules/mono/utils/naming_utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/utils/naming_utils.cpp')
-rw-r--r--modules/mono/utils/naming_utils.cpp293
1 files changed, 293 insertions, 0 deletions
diff --git a/modules/mono/utils/naming_utils.cpp b/modules/mono/utils/naming_utils.cpp
new file mode 100644
index 0000000000..dc9bc3485a
--- /dev/null
+++ b/modules/mono/utils/naming_utils.cpp
@@ -0,0 +1,293 @@
+/**************************************************************************/
+/* naming_utils.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "naming_utils.h"
+
+#include "core/string/ucaps.h"
+#include "core/templates/hash_map.h"
+
+HashMap<String, String> _create_hashmap_from_vector(Vector<Pair<String, String>> vector) {
+ HashMap<String, String> hashmap = HashMap<String, String>(vector.size());
+ for (const Pair<String, String> &pair : vector) {
+ hashmap.insert(pair.first, pair.second);
+ }
+ return hashmap;
+}
+
+// Hardcoded collection of PascalCase name conversions.
+const HashMap<String, String> pascal_case_name_overrides = _create_hashmap_from_vector({
+ { "BitMap", "Bitmap" },
+ { "JSONRPC", "JsonRpc" },
+ { "Object", "GodotObject" },
+ { "OpenXRIPBinding", "OpenXRIPBinding" },
+ { "SkeletonModification2DCCDIK", "SkeletonModification2DCcdik" },
+ { "SkeletonModification2DFABRIK", "SkeletonModification2DFabrik" },
+ { "SkeletonModification3DCCDIK", "SkeletonModification3DCcdik" },
+ { "SkeletonModification3DFABRIK", "SkeletonModification3DFabrik" },
+ { "System", "System_" },
+ { "Thread", "GodotThread" },
+});
+
+// Hardcoded collection of PascalCase part conversions.
+const HashMap<String, String> pascal_case_part_overrides = _create_hashmap_from_vector({
+ { "AA", "AA" }, // Anti Aliasing
+ { "AO", "AO" }, // Ambient Occlusion
+ { "FILENAME", "FileName" },
+ { "FADEIN", "FadeIn" },
+ { "FADEOUT", "FadeOut" },
+ { "FX", "FX" },
+ { "GI", "GI" }, // Global Illumination
+ { "GZIP", "GZip" },
+ { "HBOX", "HBox" }, // Horizontal Box
+ { "ID", "Id" },
+ { "IO", "IO" }, // Input/Output
+ { "IP", "IP" }, // Internet Protocol
+ { "IV", "IV" }, // Initialization Vector
+ { "MACOS", "MacOS" },
+ { "NODEPATH", "NodePath" },
+ { "SPIRV", "SpirV" },
+ { "STDIN", "StdIn" },
+ { "STDOUT", "StdOut" },
+ { "USERNAME", "UserName" },
+ { "UV", "UV" },
+ { "UV2", "UV2" },
+ { "VBOX", "VBox" }, // Vertical Box
+ { "WHITESPACE", "WhiteSpace" },
+ { "WM", "WM" },
+ { "XR", "XR" },
+ { "XRAPI", "XRApi" },
+});
+
+String _get_pascal_case_part_override(String p_part, bool p_input_is_upper = true) {
+ if (!p_input_is_upper) {
+ for (int i = 0; i < p_part.length(); i++) {
+ p_part[i] = _find_upper(p_part[i]);
+ }
+ }
+
+ if (pascal_case_part_overrides.has(p_part)) {
+ return pascal_case_part_overrides.get(p_part);
+ }
+
+ return String();
+}
+
+Vector<String> _split_pascal_case(const String &p_identifier) {
+ Vector<String> parts;
+ int current_part_start = 0;
+ bool prev_was_upper = is_ascii_upper_case(p_identifier[0]);
+ for (int i = 1; i < p_identifier.length(); i++) {
+ if (prev_was_upper) {
+ if (is_digit(p_identifier[i]) || is_ascii_lower_case(p_identifier[i])) {
+ if (!is_digit(p_identifier[i])) {
+ // These conditions only apply when the separator is not a digit.
+ if (i - current_part_start == 1) {
+ // Upper character was only the beggining of a word.
+ prev_was_upper = false;
+ continue;
+ }
+ if (i != p_identifier.length()) {
+ // If this is not the last character, the last uppercase
+ // character is the start of the next word.
+ i--;
+ }
+ }
+ if (i - current_part_start > 0) {
+ parts.append(p_identifier.substr(current_part_start, i - current_part_start));
+ current_part_start = i;
+ prev_was_upper = false;
+ }
+ }
+ } else {
+ if (is_digit(p_identifier[i]) || is_ascii_upper_case(p_identifier[i])) {
+ parts.append(p_identifier.substr(current_part_start, i - current_part_start));
+ current_part_start = i;
+ prev_was_upper = true;
+ }
+ }
+ }
+
+ // Add the rest of the identifier as the last part.
+ if (current_part_start != p_identifier.length()) {
+ parts.append(p_identifier.substr(current_part_start));
+ }
+
+ return parts;
+}
+
+String pascal_to_pascal_case(const String &p_identifier) {
+ if (p_identifier.length() == 0) {
+ return p_identifier;
+ }
+
+ if (p_identifier.length() <= 2) {
+ return p_identifier.to_upper();
+ }
+
+ if (pascal_case_name_overrides.has(p_identifier)) {
+ // Use hardcoded value for the identifier.
+ return pascal_case_name_overrides.get(p_identifier);
+ }
+
+ Vector<String> parts = _split_pascal_case(p_identifier);
+
+ String ret;
+
+ for (String &part : parts) {
+ String part_override = _get_pascal_case_part_override(part);
+ if (!part_override.is_empty()) {
+ // Use hardcoded value for part.
+ ret += part_override;
+ continue;
+ }
+
+ if (part.length() <= 2 && part.to_upper() == part) {
+ // Acronym of length 1 or 2.
+ for (int j = 0; j < part.length(); j++) {
+ part[j] = _find_upper(part[j]);
+ }
+ ret += part;
+ continue;
+ }
+
+ part[0] = _find_upper(part[0]);
+ for (int i = 1; i < part.length(); i++) {
+ if (is_digit(part[i - 1])) {
+ // Use uppercase after digits.
+ part[i] = _find_upper(part[i]);
+ continue;
+ }
+
+ part[i] = _find_lower(part[i]);
+ }
+ ret += part;
+ }
+
+ return ret;
+}
+
+String snake_to_pascal_case(const String &p_identifier, bool p_input_is_upper) {
+ String ret;
+ Vector<String> parts = p_identifier.split("_", true);
+
+ for (int i = 0; i < parts.size(); i++) {
+ String part = parts[i];
+
+ String part_override = _get_pascal_case_part_override(part, p_input_is_upper);
+ if (!part_override.is_empty()) {
+ // Use hardcoded value for part.
+ ret += part_override;
+ continue;
+ }
+
+ if (!part.is_empty()) {
+ part[0] = _find_upper(part[0]);
+ for (int j = 1; j < part.length(); j++) {
+ if (is_digit(part[j - 1])) {
+ // Use uppercase after digits.
+ part[j] = _find_upper(part[j]);
+ continue;
+ }
+
+ if (p_input_is_upper) {
+ part[j] = _find_lower(part[j]);
+ }
+ }
+ ret += part;
+ } else {
+ if (i == 0 || i == (parts.size() - 1)) {
+ // Preserve underscores at the beginning and end
+ ret += "_";
+ } else {
+ // Preserve contiguous underscores
+ if (parts[i - 1].length()) {
+ ret += "__";
+ } else {
+ ret += "_";
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+String snake_to_camel_case(const String &p_identifier, bool p_input_is_upper) {
+ String ret;
+ Vector<String> parts = p_identifier.split("_", true);
+
+ for (int i = 0; i < parts.size(); i++) {
+ String part = parts[i];
+
+ String part_override = _get_pascal_case_part_override(part, p_input_is_upper);
+ if (!part_override.is_empty()) {
+ // Use hardcoded value for part.
+ if (i == 0) {
+ part_override[0] = _find_lower(part_override[0]);
+ }
+ ret += part_override;
+ continue;
+ }
+
+ if (!part.is_empty()) {
+ if (i == 0) {
+ part[0] = _find_lower(part[0]);
+ } else {
+ part[0] = _find_upper(part[0]);
+ }
+ for (int j = 1; j < part.length(); j++) {
+ if (is_digit(part[j - 1])) {
+ // Use uppercase after digits.
+ part[j] = _find_upper(part[j]);
+ continue;
+ }
+
+ if (p_input_is_upper) {
+ part[j] = _find_lower(part[j]);
+ }
+ }
+ ret += part;
+ } else {
+ if (i == 0 || i == (parts.size() - 1)) {
+ // Preserve underscores at the beginning and end
+ ret += "_";
+ } else {
+ // Preserve contiguous underscores
+ if (parts[i - 1].length()) {
+ ret += "__";
+ } else {
+ ret += "_";
+ }
+ }
+ }
+ }
+
+ return ret;
+}