diff options
author | 2019-02-08 01:16:32 +0100 | |
---|---|---|
committer | 2019-02-08 01:16:32 +0100 | |
commit | fa21c9d726ebb807895a8571af9a16dab5cd8d6e (patch) | |
tree | 4597d483f90e374e89f3923324b531a56217a0f9 /cmd/binapi-generator/parse.go | |
parent | 8ba70a7b13950593aab9863246f830eda450f06b (diff) |
Generator improvements and cleanup
- generator now supports include-comments flag (as opt-in)
- minor code cleanup in binapi-generator
- remove obsolete unit tests
- flatten examples from examples/cmd folder
- introduce constant for checking compatibility in future versions
Change-Id: I3545f2ba4b869a3b51d6d0de7e742f3f1e1be392
Signed-off-by: Ondrej Fabry <ofabry@cisco.com>
Diffstat (limited to 'cmd/binapi-generator/parse.go')
-rw-r--r-- | cmd/binapi-generator/parse.go | 218 |
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 -} |