aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/binapi-generator/parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/binapi-generator/parse.go')
-rw-r--r--cmd/binapi-generator/parse.go218
1 files changed, 84 insertions, 134 deletions
diff --git a/cmd/binapi-generator/parse.go b/cmd/binapi-generator/parse.go
index 07abebd..4138ac6 100644
--- a/cmd/binapi-generator/parse.go
+++ b/cmd/binapi-generator/parse.go
@@ -23,26 +23,62 @@ import (
"github.com/bennyscetbun/jsongo"
)
+// top level objects
+const (
+ objTypes = "types"
+ objMessages = "messages"
+ objUnions = "unions"
+ objEnums = "enums"
+ objServices = "services"
+ objAliases = "aliases"
+ vlAPIVersion = "vl_api_version"
+)
+
+// various object fields
+const (
+ crcField = "crc"
+ msgIdField = "_vl_msg_id"
+
+ clientIndexField = "client_index"
+ contextField = "context"
+
+ aliasLengthField = "length"
+ aliasTypeField = "type"
+
+ replyField = "reply"
+ streamField = "stream"
+ eventsField = "events"
+)
+
+// service name parts
+const (
+ serviceEventPrefix = "want_"
+ serviceDumpSuffix = "_dump"
+ serviceDetailsSuffix = "_details"
+ serviceReplySuffix = "_reply"
+ serviceNoReply = "null"
+)
+
// parsePackage parses provided JSON data into objects prepared for code generation
func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
- logf(" %s contains: %d services, %d messages, %d types, %d enums, %d unions, %d aliases (version: %s)",
+ logf(" %s (version: %s) contains: %d services, %d messages, %d types, %d enums, %d unions, %d aliases",
ctx.packageName,
- jsonRoot.Map("services").Len(),
- jsonRoot.Map("messages").Len(),
- jsonRoot.Map("types").Len(),
- jsonRoot.Map("enums").Len(),
- jsonRoot.Map("unions").Len(),
- jsonRoot.Map("aliases").Len(),
- jsonRoot.Map("vl_api_version").Get(),
+ jsonRoot.Map(vlAPIVersion).Get(),
+ jsonRoot.Map(objServices).Len(),
+ jsonRoot.Map(objMessages).Len(),
+ jsonRoot.Map(objTypes).Len(),
+ jsonRoot.Map(objEnums).Len(),
+ jsonRoot.Map(objUnions).Len(),
+ jsonRoot.Map(objAliases).Len(),
)
pkg := Package{
- APIVersion: jsonRoot.Map("vl_api_version").Get().(string),
+ APIVersion: jsonRoot.Map(vlAPIVersion).Get().(string),
RefMap: make(map[string]string),
}
// parse enums
- enums := jsonRoot.Map("enums")
+ enums := jsonRoot.Map(objEnums)
pkg.Enums = make([]Enum, enums.Len())
for i := 0; i < enums.Len(); i++ {
enumNode := enums.At(i)
@@ -60,7 +96,7 @@ func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
})
// parse aliases
- aliases := jsonRoot.Map("aliases")
+ aliases := jsonRoot.Map(objAliases)
if aliases.GetType() == jsongo.TypeMap {
pkg.Aliases = make([]Alias, aliases.Len())
for i, key := range aliases.GetKeys() {
@@ -80,7 +116,7 @@ func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
})
// parse types
- types := jsonRoot.Map("types")
+ types := jsonRoot.Map(objTypes)
pkg.Types = make([]Type, types.Len())
for i := 0; i < types.Len(); i++ {
typNode := types.At(i)
@@ -98,7 +134,7 @@ func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
})
// parse unions
- unions := jsonRoot.Map("unions")
+ unions := jsonRoot.Map(objUnions)
pkg.Unions = make([]Union, unions.Len())
for i := 0; i < unions.Len(); i++ {
unionNode := unions.At(i)
@@ -116,7 +152,7 @@ func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
})
// parse messages
- messages := jsonRoot.Map("messages")
+ messages := jsonRoot.Map(objMessages)
pkg.Messages = make([]Message, messages.Len())
for i := 0; i < messages.Len(); i++ {
msgNode := messages.At(i)
@@ -133,7 +169,7 @@ func parsePackage(ctx *context, jsonRoot *jsongo.JSONNode) (*Package, error) {
})
// parse services
- services := jsonRoot.Map("services")
+ services := jsonRoot.Map(objServices)
if services.GetType() == jsongo.TypeMap {
pkg.Services = make([]Service, services.Len())
for i, key := range services.GetKeys() {
@@ -255,7 +291,7 @@ func parseUnion(ctx *context, unionNode *jsongo.JSONNode) (*Union, error) {
if !ok {
return nil, fmt.Errorf("union name is %T, not a string", unionNode.At(0).Get())
}
- unionCRC, ok := unionNode.At(unionNode.Len() - 1).At("crc").Get().(string)
+ unionCRC, ok := unionNode.At(unionNode.Len() - 1).At(crcField).Get().(string)
if !ok {
return nil, fmt.Errorf("union crc invalid or missing")
}
@@ -292,7 +328,7 @@ func parseType(ctx *context, typeNode *jsongo.JSONNode) (*Type, error) {
if !ok {
return nil, fmt.Errorf("type name is %T, not a string", typeNode.At(0).Get())
}
- typeCRC, ok := typeNode.At(typeNode.Len() - 1).At("crc").Get().(string)
+ typeCRC, ok := typeNode.At(typeNode.Len() - 1).At(crcField).Get().(string)
if !ok {
return nil, fmt.Errorf("type crc invalid or missing")
}
@@ -319,14 +355,9 @@ func parseType(ctx *context, typeNode *jsongo.JSONNode) (*Type, error) {
return &typ, nil
}
-const (
- aliasesLength = "length"
- aliasesType = "type"
-)
-
// parseAlias parses VPP binary API alias object from JSON node
func parseAlias(ctx *context, aliasName string, aliasNode *jsongo.JSONNode) (*Alias, error) {
- if aliasNode.Len() == 0 || aliasNode.At(aliasesType).GetType() != jsongo.TypeValue {
+ if aliasNode.Len() == 0 || aliasNode.At(aliasTypeField).GetType() != jsongo.TypeValue {
return nil, errors.New("invalid JSON for alias specified")
}
@@ -334,7 +365,7 @@ func parseAlias(ctx *context, aliasName string, aliasNode *jsongo.JSONNode) (*Al
Name: aliasName,
}
- if typeNode := aliasNode.At(aliasesType); typeNode.GetType() == jsongo.TypeValue {
+ if typeNode := aliasNode.At(aliasTypeField); typeNode.GetType() == jsongo.TypeValue {
typ, ok := typeNode.Get().(string)
if !ok {
return nil, fmt.Errorf("alias type is %T, not a string", typeNode.Get())
@@ -344,7 +375,7 @@ func parseAlias(ctx *context, aliasName string, aliasNode *jsongo.JSONNode) (*Al
}
}
- if lengthNode := aliasNode.At(aliasesLength); lengthNode.GetType() == jsongo.TypeValue {
+ if lengthNode := aliasNode.At(aliasLengthField); lengthNode.GetType() == jsongo.TypeValue {
length, ok := lengthNode.Get().(float64)
if !ok {
return nil, fmt.Errorf("alias length is %T, not a float64", lengthNode.Get())
@@ -365,7 +396,7 @@ func parseMessage(ctx *context, msgNode *jsongo.JSONNode) (*Message, error) {
if !ok {
return nil, fmt.Errorf("message name is %T, not a string", msgNode.At(0).Get())
}
- msgCRC, ok := msgNode.At(msgNode.Len() - 1).At("crc").Get().(string)
+ msgCRC, ok := msgNode.At(msgNode.Len() - 1).At(crcField).Get().(string)
if !ok {
return nil, fmt.Errorf("message crc invalid or missing")
@@ -432,7 +463,7 @@ func parseField(ctx *context, field *jsongo.JSONNode) (*Field, error) {
// parseService parses VPP binary API service object from JSON node
func parseService(ctx *context, svcName string, svcNode *jsongo.JSONNode) (*Service, error) {
- if svcNode.Len() == 0 || svcNode.At("reply").GetType() != jsongo.TypeValue {
+ if svcNode.Len() == 0 || svcNode.At(replyField).GetType() != jsongo.TypeValue {
return nil, errors.New("invalid JSON for service specified")
}
@@ -441,18 +472,18 @@ func parseService(ctx *context, svcName string, svcNode *jsongo.JSONNode) (*Serv
RequestType: svcName,
}
- if replyNode := svcNode.At("reply"); replyNode.GetType() == jsongo.TypeValue {
+ if replyNode := svcNode.At(replyField); replyNode.GetType() == jsongo.TypeValue {
reply, ok := replyNode.Get().(string)
if !ok {
return nil, fmt.Errorf("service reply is %T, not a string", replyNode.Get())
}
- if reply != "null" {
+ if reply != serviceNoReply {
svc.ReplyType = reply
}
}
// stream service (dumps)
- if streamNode := svcNode.At("stream"); streamNode.GetType() == jsongo.TypeValue {
+ if streamNode := svcNode.At(streamField); streamNode.GetType() == jsongo.TypeValue {
var ok bool
svc.Stream, ok = streamNode.Get().(bool)
if !ok {
@@ -461,7 +492,7 @@ func parseService(ctx *context, svcName string, svcNode *jsongo.JSONNode) (*Serv
}
// events service (event subscription)
- if eventsNode := svcNode.At("events"); eventsNode.GetType() == jsongo.TypeArray {
+ if eventsNode := svcNode.At(eventsField); eventsNode.GetType() == jsongo.TypeArray {
for j := 0; j < eventsNode.Len(); j++ {
event := eventsNode.At(j).Get().(string)
svc.Events = append(svc.Events, event)
@@ -469,111 +500,30 @@ func parseService(ctx *context, svcName string, svcNode *jsongo.JSONNode) (*Serv
}
// validate service
- if svc.IsEventService() {
- if !strings.HasPrefix(svc.RequestType, "want_") {
- log.Debugf("Unusual EVENTS SERVICE: %+v\n"+
- "- events service %q does not have 'want_' prefix in request.",
- svc, svc.Name)
- }
- } else if svc.IsDumpService() {
- if !strings.HasSuffix(svc.RequestType, "_dump") ||
- !strings.HasSuffix(svc.ReplyType, "_details") {
- log.Debugf("Unusual STREAM SERVICE: %+v\n"+
- "- stream service %q does not have '_dump' suffix in request or reply does not have '_details' suffix.",
- svc, svc.Name)
- }
- } else if svc.IsRequestService() {
- if !strings.HasSuffix(svc.ReplyType, "_reply") {
- log.Debugf("Unusual REQUEST SERVICE: %+v\n"+
- "- service %q does not have '_reply' suffix in reply.",
- svc, svc.Name)
+ if len(svc.Events) > 0 {
+ // EVENT service
+ if !strings.HasPrefix(svc.RequestType, serviceEventPrefix) {
+ log.Debugf("unusual EVENTS service: %+v\n"+
+ "- events service %q does not have %q prefix in request.",
+ svc, svc.Name, serviceEventPrefix)
+ }
+ } else if svc.Stream {
+ // STREAM service
+ if !strings.HasSuffix(svc.RequestType, serviceDumpSuffix) ||
+ !strings.HasSuffix(svc.ReplyType, serviceDetailsSuffix) {
+ log.Debugf("unusual STREAM service: %+v\n"+
+ "- stream service %q does not have %q suffix in request or reply does not have %q suffix.",
+ svc, svc.Name, serviceDumpSuffix, serviceDetailsSuffix)
+ }
+ } else if svc.ReplyType != "" && svc.ReplyType != serviceNoReply {
+ // REQUEST service
+ // some messages might have `null` reply (for example: memclnt)
+ if !strings.HasSuffix(svc.ReplyType, serviceReplySuffix) {
+ log.Debugf("unusual REQUEST service: %+v\n"+
+ "- service %q does not have %q suffix in reply.",
+ svc, svc.Name, serviceReplySuffix)
}
}
return &svc, nil
}
-
-// toApiType returns name that is used as type reference in VPP binary API
-func toApiType(name string) string {
- return fmt.Sprintf("vl_api_%s_t", name)
-}
-
-// convertToGoType translates the VPP binary API type into Go type
-func convertToGoType(ctx *context, binapiType string) (typ string) {
- if t, ok := binapiTypes[binapiType]; ok {
- // basic types
- typ = t
- } else if r, ok := ctx.packageData.RefMap[binapiType]; ok {
- // specific types (enums/types/unions)
- typ = camelCaseName(r)
- } else {
- switch binapiType {
- case "bool", "string":
- typ = binapiType
- default:
- // fallback type
- log.Warnf("found unknown VPP binary API type %q, using byte", binapiType)
- typ = "byte"
- }
- }
- return typ
-}
-
-func getSizeOfType(typ *Type) (size int) {
- for _, field := range typ.Fields {
- size += getSizeOfBinapiTypeLength(field.Type, field.Length)
- }
- return size
-}
-
-func getSizeOfBinapiTypeLength(typ string, length int) (size int) {
- if n := getBinapiTypeSize(typ); n > 0 {
- if length > 0 {
- return n * length
- } else {
- return n
- }
- }
- return
-}
-
-func getTypeByRef(ctx *context, ref string) *Type {
- for _, typ := range ctx.packageData.Types {
- if ref == toApiType(typ.Name) {
- return &typ
- }
- }
- return nil
-}
-
-func getAliasByRef(ctx *context, ref string) *Alias {
- for _, alias := range ctx.packageData.Aliases {
- if ref == toApiType(alias.Name) {
- return &alias
- }
- }
- return nil
-}
-
-func getUnionSize(ctx *context, union *Union) (maxSize int) {
- for _, field := range union.Fields {
- typ := getTypeByRef(ctx, field.Type)
- if typ != nil {
- if size := getSizeOfType(typ); size > maxSize {
- maxSize = size
- }
- continue
- }
- alias := getAliasByRef(ctx, field.Type)
- if alias != nil {
- if size := getSizeOfBinapiTypeLength(alias.Type, alias.Length); size > maxSize {
- maxSize = size
- }
- continue
- } else {
- logf("no type or alias found for union %s field type %q", union.Name, field.Type)
- continue
- }
- }
- return
-}