Improve binapi generator
[govpp.git] / binapigen / vppapi.go
1 //  Copyright (c) 2020 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 binapigen
16
17 import (
18         "log"
19         "sort"
20
21         "git.fd.io/govpp.git/binapigen/vppapi"
22 )
23
24 func SortFileObjectsByName(file *vppapi.File) {
25         sort.SliceStable(file.Imports, func(i, j int) bool {
26                 return file.Imports[i] < file.Imports[j]
27         })
28         sort.SliceStable(file.EnumTypes, func(i, j int) bool {
29                 return file.EnumTypes[i].Name < file.EnumTypes[j].Name
30         })
31         sort.Slice(file.AliasTypes, func(i, j int) bool {
32                 return file.AliasTypes[i].Name < file.AliasTypes[j].Name
33         })
34         sort.SliceStable(file.StructTypes, func(i, j int) bool {
35                 return file.StructTypes[i].Name < file.StructTypes[j].Name
36         })
37         sort.SliceStable(file.UnionTypes, func(i, j int) bool {
38                 return file.UnionTypes[i].Name < file.UnionTypes[j].Name
39         })
40         sort.SliceStable(file.Messages, func(i, j int) bool {
41                 return file.Messages[i].Name < file.Messages[j].Name
42         })
43         if file.Service != nil {
44                 sort.Slice(file.Service.RPCs, func(i, j int) bool {
45                         return file.Service.RPCs[i].Request < file.Service.RPCs[j].Request
46                 })
47         }
48 }
49
50 func importedFiles(files []*vppapi.File, file *vppapi.File) []*vppapi.File {
51         var list []*vppapi.File
52         byName := func(s string) *vppapi.File {
53                 for _, f := range files {
54                         if f.Name == s {
55                                 return f
56                         }
57                 }
58                 return nil
59         }
60         imported := map[string]struct{}{}
61         for _, imp := range file.Imports {
62                 imp = normalizeImport(imp)
63                 impFile := byName(imp)
64                 if impFile == nil {
65                         log.Fatalf("file %q not found", imp)
66                 }
67                 for _, nest := range importedFiles(files, impFile) {
68                         if _, ok := imported[nest.Name]; !ok {
69                                 list = append(list, nest)
70                                 imported[nest.Name] = struct{}{}
71                         }
72                 }
73                 if _, ok := imported[impFile.Name]; !ok {
74                         list = append(list, impFile)
75                         imported[impFile.Name] = struct{}{}
76                 }
77         }
78         return list
79 }
80
81 func SortFilesByImports(apifiles []*vppapi.File) {
82         dependsOn := func(file *vppapi.File, dep string) bool {
83                 for _, imp := range importedFiles(apifiles, file) {
84                         if imp.Name == dep {
85                                 return true
86                         }
87                 }
88                 return false
89         }
90         sort.Slice(apifiles, func(i, j int) bool {
91                 a := apifiles[i]
92                 b := apifiles[j]
93                 if dependsOn(a, b.Name) {
94                         return false
95                 }
96                 if dependsOn(b, a.Name) {
97                         return true
98                 }
99                 return len(b.Imports) > len(a.Imports)
100         })
101 }
102
103 func ListImportedTypes(apifiles []*vppapi.File, file *vppapi.File) []string {
104         var importedTypes []string
105         typeFiles := importedFiles(apifiles, file)
106         for _, t := range file.StructTypes {
107                 var imported bool
108                 for _, imp := range typeFiles {
109                         for _, at := range imp.StructTypes {
110                                 if at.Name != t.Name {
111                                         continue
112                                 }
113                                 importedTypes = append(importedTypes, t.Name)
114                                 imported = true
115                                 break
116                         }
117                         if imported {
118                                 break
119                         }
120                 }
121         }
122         for _, t := range file.AliasTypes {
123                 var imported bool
124                 for _, imp := range typeFiles {
125                         for _, at := range imp.AliasTypes {
126                                 if at.Name != t.Name {
127                                         continue
128                                 }
129                                 importedTypes = append(importedTypes, t.Name)
130                                 imported = true
131                                 break
132                         }
133                         if imported {
134                                 break
135                         }
136                 }
137         }
138         for _, t := range file.EnumTypes {
139                 var imported bool
140                 for _, imp := range typeFiles {
141                         for _, at := range imp.EnumTypes {
142                                 if at.Name != t.Name {
143                                         continue
144                                 }
145                                 importedTypes = append(importedTypes, t.Name)
146                                 imported = true
147                                 break
148                         }
149                         if imported {
150                                 break
151                         }
152                 }
153         }
154         for _, t := range file.UnionTypes {
155                 var imported bool
156                 for _, imp := range typeFiles {
157                         for _, at := range imp.UnionTypes {
158                                 if at.Name != t.Name {
159                                         continue
160                                 }
161                                 importedTypes = append(importedTypes, t.Name)
162                                 imported = true
163                                 break
164                         }
165                         if imported {
166                                 break
167                         }
168                 }
169         }
170         return importedTypes
171 }
172
173 func RemoveImportedTypes(apifiles []*vppapi.File, apifile *vppapi.File) {
174         importedTypes := ListImportedTypes(apifiles, apifile)
175         isImportedType := func(s string) bool {
176                 for _, t := range importedTypes {
177                         if t == s {
178                                 return true
179                         }
180                 }
181                 return false
182         }
183         var enums []vppapi.EnumType
184         for _, enumType := range apifile.EnumTypes {
185                 if !isImportedType(enumType.Name) {
186                         enums = append(enums, enumType)
187                 }
188         }
189         var aliases []vppapi.AliasType
190         for _, aliasType := range apifile.AliasTypes {
191                 if !isImportedType(aliasType.Name) {
192                         aliases = append(aliases, aliasType)
193                 }
194         }
195         var structs []vppapi.StructType
196         for _, structType := range apifile.StructTypes {
197                 if !isImportedType(structType.Name) {
198                         structs = append(structs, structType)
199                 }
200         }
201         var unions []vppapi.UnionType
202         for _, unionType := range apifile.UnionTypes {
203                 if !isImportedType(unionType.Name) {
204                         unions = append(unions, unionType)
205                 }
206         }
207         apifile.EnumTypes = enums
208         apifile.AliasTypes = aliases
209         apifile.StructTypes = structs
210         apifile.UnionTypes = unions
211 }