Skip to content

Commit

Permalink
Change the camelcase algorithm to be consistent with earlier
Browse files Browse the repository at this point in the history
implementations (copy the google-internal version).
The difference is that lower-case letters are always capitalized
if the preceding character is not an upper-case letter.

R=rsc
CC=dsymonds1
http://codereview.appspot.com/1599045
  • Loading branch information
robpike committed Jun 10, 2010
1 parent c9e7d97 commit 2c7bafc
Showing 1 changed file with 55 additions and 20 deletions.
75 changes: 55 additions & 20 deletions compiler/generator/generator.go
Expand Up @@ -1042,30 +1042,65 @@ func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) {

// And now lots of helper functions.

// CamelCase returns the CamelCased name. Given foo_bar_Baz, the result is FooBar_Baz.
func CamelCase(name string) string {
elems := strings.Split(name, "_", 0)
for i, e := range elems {
if e == "" {
elems[i] = "_"
// Is c an ASCII lower-case letter?
func isASCIILower(c byte) bool {
return 'a' <= c && c <= 'z'
}

// Is c an ASCII digit?
func isASCIIDigit(c byte) bool {
return '0' <= c && c <= '9'
}

// CamelCase returns the CamelCased name.
// If there is an interior underscore followed by a lower case letter,
// drop the underscore and convert the letter to upper case.
// There is a remote possibility of this rewrite causing a name collision,
// but it's so remote we're prepared to pretend it's nonexistent - since the
// C++ generator lowercases names, it's extremely unlikely to have two fields
// with different capitalizations.
// In short, _my_field_name_2 becomes XMyFieldName2.
func CamelCase(s string) string {
if s == "" {
return ""
}
t := make([]byte, 0, 32)
oneC := make([]byte, 1)
i := 0
if s[0] == '_' {
// Need a capital letter; drop the '_'.
oneC[0] = 'X'
t = bytes.Add(t, oneC)
i++
}
// Invariant: if the next letter is lower case, it must be converted
// to upper case.
// That is, we process a word at a time, where words are marked by _ or
// upper case letter. Digits are treated as words.
for ; i < len(s); i++ {
c := s[i]
oneC[0] = c
if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
continue // Skip the underscore in s.
}
if isASCIIDigit(c) {
t = bytes.Add(t, oneC)
continue
}
runes := []int(e)
if unicode.IsLower(runes[0]) {
runes[0] = unicode.ToUpper(runes[0])
elems[i] = string(runes)
} else {
if i > 0 {
elems[i] = "_" + e
}
// Assume we have a letter now - if not, it's a bogus identifier.
// The next word is a sequence of characters that must start upper case.
if isASCIILower(c) {
oneC[0] ^= ' ' // Make it a capital letter.
}
t = bytes.Add(t, oneC) // Guaranteed not lower case.
// Accept lower case sequence that follows.
for i+1 < len(s) && isASCIILower(s[i+1]) {
i++
oneC[0] = s[i]
t = bytes.Add(t, oneC)
}
}
s := strings.Join(elems, "")
// Name must not begin with an underscore.
if len(s) > 0 && s[0] == '_' {
s = "X" + s[1:]
}
return s
return string(t)
}

// CamelCaseSlice is like CamelCase, but the argument is a slice of strings to
Expand Down

0 comments on commit 2c7bafc

Please sign in to comment.