01762781a3a29766c9e6032ec684eeb063becff6
[govpp.git] / cmd / binapi-generator / definitions.go
1 // Copyright (c) 2018 Cisco and/or its affiliates.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package main
16
17 import (
18         "strconv"
19         "strings"
20         "unicode"
21 )
22
23 func getBinapiTypeSize(binapiType string) int {
24         if _, ok := binapiTypes[binapiType]; ok {
25                 b, err := strconv.Atoi(strings.TrimLeft(binapiType, "uif"))
26                 if err == nil {
27                         return b / 8
28                 } else {
29                         return 1
30                 }
31         }
32         return -1
33 }
34
35 // binapiTypes is a set of types used VPP binary API for translation to Go types
36 var binapiTypes = map[string]string{
37         "bool": "bool",
38         "u8":   "uint8",
39         "i8":   "int8",
40         "u16":  "uint16",
41         "i16":  "int16",
42         "u32":  "uint32",
43         "i32":  "int32",
44         "u64":  "uint64",
45         "i64":  "int64",
46         "f64":  "float64",
47 }
48
49 func usesInitialism(s string) string {
50         if u := strings.ToUpper(s); commonInitialisms[u] {
51                 return u
52         } else if su, ok := specialInitialisms[u]; ok {
53                 return su
54         }
55         return ""
56 }
57
58 // commonInitialisms is a set of common initialisms that need to stay in upper case.
59 var commonInitialisms = map[string]bool{
60         "ACL": true,
61         "API": true,
62         //"ASCII": true, // there are only two use cases for ASCII which already have initialism before and after
63         "CPU":   true,
64         "CSS":   true,
65         "DNS":   true,
66         "DHCP":  true,
67         "EOF":   true,
68         "GUID":  true,
69         "HTML":  true,
70         "HTTP":  true,
71         "HTTPS": true,
72         "ID":    true,
73         "IP":    true,
74         "ICMP":  true,
75         "JSON":  true,
76         "LHS":   true,
77         "QPS":   true,
78         "PID":   true,
79         "RAM":   true,
80         "RHS":   true,
81         "RPC":   true,
82         "SLA":   true,
83         "SMTP":  true,
84         "SQL":   true,
85         "SSH":   true,
86         "TCP":   true,
87         "TLS":   true,
88         "TTL":   true,
89         "UDP":   true,
90         "UI":    true,
91         "UID":   true,
92         "UUID":  true,
93         "URI":   true,
94         "URL":   true,
95         "UTF8":  true,
96         "VM":    true,
97         "VPN":   true,
98         "XML":   true,
99         "XMPP":  true,
100         "XSRF":  true,
101         "XSS":   true,
102 }
103
104 // specialInitialisms is a set of special initialisms that need part to stay in upper case.
105 var specialInitialisms = map[string]string{
106         "IPV": "IPv",
107         //"IPV4": "IPv4",
108         //"IPV6": "IPv6",
109 }
110
111 // camelCaseName returns correct name identifier (camelCase).
112 func camelCaseName(name string) (should string) {
113         name = strings.Title(name)
114
115         // Fast path for simple cases: "_" and all lowercase.
116         if name == "_" {
117                 return name
118         }
119         allLower := true
120         for _, r := range name {
121                 if !unicode.IsLower(r) {
122                         allLower = false
123                         break
124                 }
125         }
126         if allLower {
127                 return name
128         }
129
130         // Split camelCase at any lower->upper transition, and split on underscores.
131         // Check each word for common initialisms.
132         runes := []rune(name)
133         w, i := 0, 0 // index of start of word, scan
134         for i+1 <= len(runes) {
135                 eow := false // whether we hit the end of a word
136                 if i+1 == len(runes) {
137                         eow = true
138                 } else if runes[i+1] == '_' {
139                         // underscore; shift the remainder forward over any run of underscores
140                         eow = true
141                         n := 1
142                         for i+n+1 < len(runes) && runes[i+n+1] == '_' {
143                                 n++
144                         }
145
146                         // Leave at most one underscore if the underscore is between two digits
147                         if i+n+1 < len(runes) && unicode.IsDigit(runes[i]) && unicode.IsDigit(runes[i+n+1]) {
148                                 n--
149                         }
150
151                         copy(runes[i+1:], runes[i+n+1:])
152                         runes = runes[:len(runes)-n]
153                 } else if unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]) {
154                         // lower->non-lower
155                         eow = true
156                 }
157                 i++
158                 if !eow {
159                         continue
160                 }
161
162                 // [w,i) is a word.
163                 word := string(runes[w:i])
164                 if u := usesInitialism(word); u != "" {
165                         // Keep consistent case, which is lowercase only at the start.
166                         if w == 0 && unicode.IsLower(runes[w]) {
167                                 u = strings.ToLower(u)
168                         }
169                         // All the common initialisms are ASCII,
170                         // so we can replace the bytes exactly.
171                         copy(runes[w:], []rune(u))
172                 } else if w > 0 && strings.ToLower(word) == word {
173                         // already all lowercase, and not the first word, so uppercase the first character.
174                         runes[w] = unicode.ToUpper(runes[w])
175                 }
176                 w = i
177         }
178         return string(runes)
179 }