Protobuf Team Bot | e2aa06e | 2023-02-10 14:11:22 -0800 | [diff] [blame] | 1 | """Starlark helpers for Objective-C protos.""" |
| 2 | |
| 3 | # State constants for objc_proto_camel_case_name. |
| 4 | _last_was_other = 0 |
| 5 | _last_was_lowercase = 1 |
| 6 | _last_was_uppercase = 2 |
| 7 | _last_was_number = 3 |
| 8 | |
| 9 | def objc_proto_camel_case_name(name): |
| 10 | """A Starlark version of the ObjC generator's CamelCase name transform. |
| 11 | |
| 12 | This needs to track |
| 13 | src/google/protobuf/compiler/objectivec/names.cc's UnderscoresToCamelCase() |
| 14 | |
| 15 | NOTE: This code is written to model the C++ in protoc's ObjC generator so it |
| 16 | is easier to confirm that the algorithms between the implementations match. |
| 17 | The customizations for starlark performance are: |
| 18 | - The cascade within the loop is reordered and special cases "_" to |
| 19 | optimize for google3 inputs. |
| 20 | - The "last was" state is handled via integers instead of three booleans. |
| 21 | |
| 22 | The `first_capitalized` argument in the C++ code is left off this code and |
| 23 | it acts as if the value were `True`. |
| 24 | |
| 25 | Args: |
| 26 | name: The proto file name to convert to camel case. The extension should |
| 27 | already be removed. |
| 28 | |
| 29 | Returns: |
| 30 | The converted proto name to camel case. |
| 31 | """ |
| 32 | segments = [] |
| 33 | current = "" |
| 34 | last_was = _last_was_other |
| 35 | for c in name.elems(): |
| 36 | if c.islower(): |
| 37 | # lowercase letter can follow a lowercase or uppercase letter. |
| 38 | if last_was != _last_was_lowercase and last_was != _last_was_uppercase: |
| 39 | segments.append(current) |
| 40 | current = c.upper() |
| 41 | else: |
| 42 | current += c |
| 43 | last_was = _last_was_lowercase |
| 44 | elif c == "_": # more common than rest, special case it. |
| 45 | last_was = _last_was_other |
| 46 | elif c.isdigit(): |
| 47 | if last_was != _last_was_number: |
| 48 | segments.append(current) |
| 49 | current = "" |
| 50 | current += c |
| 51 | last_was = _last_was_number |
| 52 | elif c.isupper(): |
| 53 | if last_was != _last_was_uppercase: |
| 54 | segments.append(current) |
| 55 | current = c |
| 56 | else: |
| 57 | current += c.lower() |
| 58 | last_was = _last_was_uppercase |
| 59 | else: |
| 60 | last_was = _last_was_other |
| 61 | segments.append(current) |
| 62 | result = "" |
| 63 | for x in segments: |
| 64 | if x in ("Url", "Http", "Https"): |
| 65 | result += x.upper() |
| 66 | else: |
| 67 | result += x |
| 68 | return result |