1 // Copyright (c) 2020 Cisco and/or its affiliates.
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:
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
23 "git.fd.io/govpp.git/binapigen/vppapi"
40 imports map[string]string
41 refmap map[string]string
44 func newFile(gen *Generator, apifile *vppapi.File) (*File, error) {
47 PackageName: sanitizedName(apifile.Name),
48 imports: make(map[string]string),
49 refmap: make(map[string]string),
52 sortFileObjects(&file.File)
54 for _, imp := range apifile.Imports {
55 file.Imports = append(file.Imports, normalizeImport(imp))
57 for _, enum := range apifile.EnumTypes {
58 file.Enums = append(file.Enums, newEnum(gen, file, enum))
60 for _, alias := range apifile.AliasTypes {
61 file.Aliases = append(file.Aliases, newAlias(gen, file, alias))
63 for _, structType := range apifile.StructTypes {
64 file.Structs = append(file.Structs, newStruct(gen, file, structType))
66 for _, union := range apifile.UnionTypes {
67 file.Unions = append(file.Unions, newUnion(gen, file, union))
69 for _, msg := range apifile.Messages {
70 file.Messages = append(file.Messages, newMessage(gen, file, msg))
76 func (file *File) isTypes() bool {
77 return strings.HasSuffix(file.File.Name, "_types")
80 func (file *File) hasService() bool {
81 return file.Service != nil && len(file.Service.RPCs) > 0
84 func (file *File) addRef(typ string, name string, ref interface{}) {
85 apiName := toApiType(name)
86 if _, ok := file.refmap[apiName]; ok {
87 logf("%s type %v already in refmap", typ, apiName)
90 file.refmap[apiName] = name
93 func (file *File) importedFiles(gen *Generator) []*File {
95 for _, imp := range file.Imports {
96 impFile, ok := gen.FilesByName[imp]
98 logf("file %s import %s not found API files", file.Name, imp)
101 //if gen.ImportTypes || impFile.Generate {
102 files = append(files, impFile)
108 func (file *File) loadTypeImports(gen *Generator, typeFiles []*File) {
109 if len(typeFiles) == 0 {
112 for _, t := range file.Structs {
113 for _, imp := range typeFiles {
114 if _, ok := file.imports[t.Name]; ok {
117 for _, at := range imp.File.StructTypes {
118 if at.Name != t.Name {
121 if len(at.Fields) != len(t.Fields) {
124 file.imports[t.Name] = imp.PackageName
128 for _, t := range file.AliasTypes {
129 for _, imp := range typeFiles {
130 if _, ok := file.imports[t.Name]; ok {
133 for _, at := range imp.File.AliasTypes {
134 if at.Name != t.Name {
137 if at.Length != t.Length {
140 if at.Type != t.Type {
143 file.imports[t.Name] = imp.PackageName
147 for _, t := range file.EnumTypes {
148 for _, imp := range typeFiles {
149 if _, ok := file.imports[t.Name]; ok {
152 for _, at := range imp.File.EnumTypes {
153 if at.Name != t.Name {
156 if at.Type != t.Type {
159 file.imports[t.Name] = imp.PackageName
163 for _, t := range file.UnionTypes {
164 for _, imp := range typeFiles {
165 if _, ok := file.imports[t.Name]; ok {
168 for _, at := range imp.File.UnionTypes {
169 if at.Name != t.Name {
172 file.imports[t.Name] = imp.PackageName
173 /*if gen.ImportTypes {
187 func newEnum(gen *Generator, file *File, apitype vppapi.EnumType) *Enum {
190 GoName: camelCaseName(apitype.Name),
192 gen.enumsByName[fmt.Sprintf("%s.%s", file.Name, typ.Name)] = typ
193 file.addRef("enum", typ.Name, typ)
203 func newAlias(gen *Generator, file *File, apitype vppapi.AliasType) *Alias {
206 GoName: camelCaseName(apitype.Name),
208 gen.aliasesByName[fmt.Sprintf("%s.%s", file.Name, typ.Name)] = typ
209 file.addRef("alias", typ.Name, typ)
221 func newStruct(gen *Generator, file *File, apitype vppapi.StructType) *Struct {
224 GoName: camelCaseName(apitype.Name),
226 for _, fieldType := range apitype.Fields {
227 field := newField(gen, file, fieldType)
228 field.ParentStruct = typ
229 typ.Fields = append(typ.Fields, field)
231 gen.structsByName[fmt.Sprintf("%s.%s", file.Name, typ.Name)] = typ
232 file.addRef("struct", typ.Name, typ)
244 func newUnion(gen *Generator, file *File, apitype vppapi.UnionType) *Union {
247 GoName: camelCaseName(apitype.Name),
249 gen.unionsByName[fmt.Sprintf("%s.%s", file.Name, typ.Name)] = typ
250 for _, fieldType := range apitype.Fields {
251 field := newField(gen, file, fieldType)
252 field.ParentUnion = typ
253 typ.Fields = append(typ.Fields, field)
255 file.addRef("union", typ.Name, typ)
259 type Message struct {
267 func newMessage(gen *Generator, file *File, apitype vppapi.Message) *Message {
270 GoName: camelCaseName(apitype.Name),
272 for _, fieldType := range apitype.Fields {
273 field := newField(gen, file, fieldType)
274 field.ParentMessage = msg
275 msg.Fields = append(msg.Fields, field)
286 ParentMessage *Message
297 func newField(gen *Generator, file *File, apitype vppapi.Field) *Field {
300 GoName: camelCaseName(apitype.Name),
305 func (f *Field) resolveType(gen *Generator) error {
312 type Service = vppapi.Service
313 type RPC = vppapi.RPC
315 func sortFileObjects(file *vppapi.File) {
317 sort.SliceStable(file.Imports, func(i, j int) bool {
318 return file.Imports[i] < file.Imports[j]
321 sort.SliceStable(file.EnumTypes, func(i, j int) bool {
322 return file.EnumTypes[i].Name < file.EnumTypes[j].Name
325 sort.Slice(file.AliasTypes, func(i, j int) bool {
326 return file.AliasTypes[i].Name < file.AliasTypes[j].Name
329 sort.SliceStable(file.StructTypes, func(i, j int) bool {
330 return file.StructTypes[i].Name < file.StructTypes[j].Name
333 sort.SliceStable(file.UnionTypes, func(i, j int) bool {
334 return file.UnionTypes[i].Name < file.UnionTypes[j].Name
337 sort.SliceStable(file.Messages, func(i, j int) bool {
338 return file.Messages[i].Name < file.Messages[j].Name
341 if file.Service != nil {
342 sort.Slice(file.Service.RPCs, func(i, j int) bool {
344 if file.Service.RPCs[i].Stream != file.Service.RPCs[j].Stream {
345 return file.Service.RPCs[i].Stream
347 return file.Service.RPCs[i].RequestMsg < file.Service.RPCs[j].RequestMsg
352 func sanitizedName(name string) string {
363 func normalizeImport(imp string) string {
365 if idx := strings.Index(imp, "."); idx >= 0 {