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