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.go557
1 files changed, 0 insertions, 557 deletions
diff --git a/cmd/binapi-generator/parse.go b/cmd/binapi-generator/parse.go
deleted file mode 100644
index 6598b7b..0000000
--- a/cmd/binapi-generator/parse.go
+++ /dev/null
@@ -1,557 +0,0 @@
-// Copyright (c) 2018 Cisco and/or its affiliates.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at:
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
- "errors"
- "fmt"
- "sort"
- "strings"
-
- "github.com/bennyscetbun/jsongo"
- "github.com/sirupsen/logrus"
-)
-
-// top level objects
-const (
- objTypes = "types"
- objMessages = "messages"
- objUnions = "unions"
- objEnums = "enums"
- objServices = "services"
- objAliases = "aliases"
- vlAPIVersion = "vl_api_version"
- objOptions = "options"
-)
-
-// 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"
-)
-
-// field meta info
-const (
- fieldMetaLimit = "limit"
- fieldMetaDefault = "default"
-)
-
-// module options
-const (
- versionOption = "version"
-)
-
-// parsePackage parses provided JSON data into objects prepared for code generation
-func parsePackage(ctx *context, jsonRoot *jsongo.Node) (*Package, error) {
- pkg := Package{
- Name: ctx.packageName,
- RefMap: make(map[string]string),
- Imports: map[string]Import{},
- }
-
- // parse CRC for API version
- if crc := jsonRoot.At(vlAPIVersion); crc.GetType() == jsongo.TypeValue {
- pkg.CRC = crc.Get().(string)
- }
-
- // parse version string
- if opt := jsonRoot.Map(objOptions); opt.GetType() == jsongo.TypeMap {
- if ver := opt.Map(versionOption); ver.GetType() == jsongo.TypeValue {
- pkg.Version = ver.Get().(string)
- }
- }
-
- logf("parsing package %s (version: %s, CRC: %s)", pkg.Name, pkg.Version, pkg.CRC)
- logf(" consists of:")
- for _, key := range jsonRoot.GetKeys() {
- logf(" - %d %s", jsonRoot.At(key).Len(), key)
- }
-
- // parse enums
- enums := jsonRoot.Map(objEnums)
- pkg.Enums = make([]Enum, 0)
- for i := 0; i < enums.Len(); i++ {
- enumNode := enums.At(i)
-
- enum, err := parseEnum(ctx, enumNode)
- if err != nil {
- return nil, err
- }
-
- enumApi := toApiType(enum.Name)
- if _, ok := pkg.RefMap[enumApi]; ok {
- logf("enum %v already known", enumApi)
- continue
- }
- pkg.RefMap[enumApi] = enum.Name
- pkg.Enums = append(pkg.Enums, *enum)
- }
- // sort enums
- sort.SliceStable(pkg.Enums, func(i, j int) bool {
- return pkg.Enums[i].Name < pkg.Enums[j].Name
- })
-
- // parse aliases
- aliases := jsonRoot.Map(objAliases)
- if aliases.GetType() == jsongo.TypeMap {
- pkg.Aliases = make([]Alias, 0)
- for _, key := range aliases.GetKeys() {
- aliasNode := aliases.At(key)
-
- alias, err := parseAlias(ctx, key.(string), aliasNode)
- if err != nil {
- return nil, err
- }
-
- aliasApi := toApiType(alias.Name)
- if _, ok := pkg.RefMap[aliasApi]; ok {
- logf("alias %v already known", aliasApi)
- continue
- }
- pkg.RefMap[aliasApi] = alias.Name
- pkg.Aliases = append(pkg.Aliases, *alias)
- }
- }
- // sort aliases to ensure consistent order
- sort.Slice(pkg.Aliases, func(i, j int) bool {
- return pkg.Aliases[i].Name < pkg.Aliases[j].Name
- })
-
- // parse types
- types := jsonRoot.Map(objTypes)
- pkg.Types = make([]Type, 0)
- for i := 0; i < types.Len(); i++ {
- typNode := types.At(i)
-
- typ, err := parseType(ctx, typNode)
- if err != nil {
- return nil, err
- }
-
- typApi := toApiType(typ.Name)
- if _, ok := pkg.RefMap[typApi]; ok {
- logf("type %v already known", typApi)
- continue
- }
- pkg.RefMap[typApi] = typ.Name
- pkg.Types = append(pkg.Types, *typ)
- }
- // sort types
- sort.SliceStable(pkg.Types, func(i, j int) bool {
- return pkg.Types[i].Name < pkg.Types[j].Name
- })
-
- // parse unions
- unions := jsonRoot.Map(objUnions)
- pkg.Unions = make([]Union, 0)
- for i := 0; i < unions.Len(); i++ {
- unionNode := unions.At(i)
-
- union, err := parseUnion(ctx, unionNode)
- if err != nil {
- return nil, err
- }
-
- unionApi := toApiType(union.Name)
- if _, ok := pkg.RefMap[unionApi]; ok {
- logf("union %v already known", unionApi)
- continue
- }
- pkg.RefMap[unionApi] = union.Name
- pkg.Unions = append(pkg.Unions, *union)
- }
- // sort unions
- sort.SliceStable(pkg.Unions, func(i, j int) bool {
- return pkg.Unions[i].Name < pkg.Unions[j].Name
- })
-
- // parse messages
- messages := jsonRoot.Map(objMessages)
- pkg.Messages = make([]Message, messages.Len())
- for i := 0; i < messages.Len(); i++ {
- msgNode := messages.At(i)
-
- msg, err := parseMessage(ctx, msgNode)
- if err != nil {
- return nil, err
- }
- pkg.Messages[i] = *msg
- }
- // sort messages
- sort.SliceStable(pkg.Messages, func(i, j int) bool {
- return pkg.Messages[i].Name < pkg.Messages[j].Name
- })
-
- // parse services
- services := jsonRoot.Map(objServices)
- if services.GetType() == jsongo.TypeMap {
- pkg.Services = make([]Service, services.Len())
- for i, key := range services.GetKeys() {
- svcNode := services.At(key)
-
- svc, err := parseService(ctx, key.(string), svcNode)
- if err != nil {
- return nil, err
- }
- pkg.Services[i] = *svc
- }
- }
- // sort services
- sort.Slice(pkg.Services, func(i, j int) bool {
- // dumps first
- if pkg.Services[i].Stream != pkg.Services[j].Stream {
- return pkg.Services[i].Stream
- }
- return pkg.Services[i].RequestType < pkg.Services[j].RequestType
- })
-
- printPackage(&pkg)
-
- return &pkg, nil
-}
-
-// parseEnum parses VPP binary API enum object from JSON node
-func parseEnum(ctx *context, enumNode *jsongo.Node) (*Enum, error) {
- if enumNode.Len() == 0 || enumNode.At(0).GetType() != jsongo.TypeValue {
- return nil, errors.New("invalid JSON for enum specified")
- }
-
- enumName, ok := enumNode.At(0).Get().(string)
- if !ok {
- return nil, fmt.Errorf("enum name is %T, not a string", enumNode.At(0).Get())
- }
- enumType, ok := enumNode.At(enumNode.Len() - 1).At("enumtype").Get().(string)
- if !ok {
- return nil, fmt.Errorf("enum type invalid or missing")
- }
-
- enum := Enum{
- Name: enumName,
- Type: enumType,
- }
-
- // loop through enum entries, skip first (name) and last (enumtype)
- for j := 1; j < enumNode.Len()-1; j++ {
- if enumNode.At(j).GetType() == jsongo.TypeArray {
- entry := enumNode.At(j)
-
- if entry.Len() < 2 || entry.At(0).GetType() != jsongo.TypeValue || entry.At(1).GetType() != jsongo.TypeValue {
- return nil, errors.New("invalid JSON for enum entry specified")
- }
-
- entryName, ok := entry.At(0).Get().(string)
- if !ok {
- return nil, fmt.Errorf("enum entry name is %T, not a string", entry.At(0).Get())
- }
- entryVal := entry.At(1).Get()
-
- enum.Entries = append(enum.Entries, EnumEntry{
- Name: entryName,
- Value: entryVal,
- })
- }
- }
-
- return &enum, nil
-}
-
-// parseUnion parses VPP binary API union object from JSON node
-func parseUnion(ctx *context, unionNode *jsongo.Node) (*Union, error) {
- if unionNode.Len() == 0 || unionNode.At(0).GetType() != jsongo.TypeValue {
- return nil, errors.New("invalid JSON for union specified")
- }
-
- unionName, ok := unionNode.At(0).Get().(string)
- if !ok {
- return nil, fmt.Errorf("union name is %T, not a string", unionNode.At(0).Get())
- }
- var unionCRC string
- if unionNode.At(unionNode.Len()-1).GetType() == jsongo.TypeMap {
- unionCRC = unionNode.At(unionNode.Len() - 1).At(crcField).Get().(string)
- }
-
- union := Union{
- Name: unionName,
- CRC: unionCRC,
- }
-
- // loop through union fields, skip first (name)
- for j := 1; j < unionNode.Len(); j++ {
- if unionNode.At(j).GetType() == jsongo.TypeArray {
- fieldNode := unionNode.At(j)
-
- field, err := parseField(ctx, fieldNode)
- if err != nil {
- return nil, err
- }
-
- union.Fields = append(union.Fields, *field)
- }
- }
-
- return &union, nil
-}
-
-// parseType parses VPP binary API type object from JSON node
-func parseType(ctx *context, typeNode *jsongo.Node) (*Type, error) {
- if typeNode.Len() == 0 || typeNode.At(0).GetType() != jsongo.TypeValue {
- return nil, errors.New("invalid JSON for type specified")
- }
-
- typeName, ok := typeNode.At(0).Get().(string)
- if !ok {
- return nil, fmt.Errorf("type name is %T, not a string", typeNode.At(0).Get())
- }
- var typeCRC string
- if lastField := typeNode.At(typeNode.Len() - 1); lastField.GetType() == jsongo.TypeMap {
- typeCRC = lastField.At(crcField).Get().(string)
- }
-
- typ := Type{
- Name: typeName,
- CRC: typeCRC,
- }
-
- // loop through type fields, skip first (name)
- for j := 1; j < typeNode.Len(); j++ {
- if typeNode.At(j).GetType() == jsongo.TypeArray {
- fieldNode := typeNode.At(j)
-
- field, err := parseField(ctx, fieldNode)
- if err != nil {
- return nil, err
- }
-
- typ.Fields = append(typ.Fields, *field)
- }
- }
-
- return &typ, nil
-}
-
-// parseAlias parses VPP binary API alias object from JSON node
-func parseAlias(ctx *context, aliasName string, aliasNode *jsongo.Node) (*Alias, error) {
- if aliasNode.Len() == 0 || aliasNode.At(aliasTypeField).GetType() != jsongo.TypeValue {
- return nil, errors.New("invalid JSON for alias specified")
- }
-
- alias := Alias{
- Name: aliasName,
- }
-
- 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())
- }
- if typ != "null" {
- alias.Type = typ
- }
- }
-
- 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())
- }
- alias.Length = int(length)
- }
-
- return &alias, nil
-}
-
-// parseMessage parses VPP binary API message object from JSON node
-func parseMessage(ctx *context, msgNode *jsongo.Node) (*Message, error) {
- if msgNode.Len() == 0 || msgNode.At(0).GetType() != jsongo.TypeValue {
- return nil, errors.New("invalid JSON for message specified")
- }
-
- msgName, ok := msgNode.At(0).Get().(string)
- 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(crcField).Get().(string)
- if !ok {
-
- return nil, fmt.Errorf("message crc invalid or missing")
- }
-
- msg := Message{
- Name: msgName,
- CRC: msgCRC,
- }
-
- // loop through message fields, skip first (name) and last (crc)
- for j := 1; j < msgNode.Len()-1; j++ {
- if msgNode.At(j).GetType() == jsongo.TypeArray {
- fieldNode := msgNode.At(j)
-
- field, err := parseField(ctx, fieldNode)
- if err != nil {
- return nil, err
- }
-
- msg.Fields = append(msg.Fields, *field)
- }
- }
-
- return &msg, nil
-}
-
-// parseField parses VPP binary API object field from JSON node
-func parseField(ctx *context, field *jsongo.Node) (*Field, error) {
- if field.Len() < 2 || field.At(0).GetType() != jsongo.TypeValue || field.At(1).GetType() != jsongo.TypeValue {
- return nil, errors.New("invalid JSON for field specified")
- }
-
- fieldType, ok := field.At(0).Get().(string)
- if !ok {
- return nil, fmt.Errorf("field type is %T, not a string", field.At(0).Get())
- }
- fieldName, ok := field.At(1).Get().(string)
- if !ok {
- return nil, fmt.Errorf("field name is %T, not a string", field.At(1).Get())
- }
-
- f := &Field{
- Name: fieldName,
- Type: fieldType,
- }
-
- if field.Len() >= 3 {
- switch field.At(2).GetType() {
- case jsongo.TypeValue:
- fieldLength, ok := field.At(2).Get().(float64)
- if !ok {
- return nil, fmt.Errorf("field length is %T, not float64", field.At(2).Get())
- }
- f.Length = int(fieldLength)
- f.SpecifiedLen = true
-
- case jsongo.TypeMap:
- fieldMeta := field.At(2)
-
- for _, key := range fieldMeta.GetKeys() {
- metaNode := fieldMeta.At(key)
-
- switch metaName := key.(string); metaName {
- case fieldMetaLimit:
- f.Meta.Limit = int(metaNode.Get().(float64))
- case fieldMetaDefault:
- f.Meta.Default = fmt.Sprint(metaNode.Get())
- default:
- logrus.Warnf("unknown meta info (%s) for field (%s)", metaName, fieldName)
- }
- }
- default:
- return nil, errors.New("invalid JSON for field specified")
- }
- }
- if field.Len() >= 4 {
- fieldLengthFrom, ok := field.At(3).Get().(string)
- if !ok {
- return nil, fmt.Errorf("field length from is %T, not a string", field.At(3).Get())
- }
- f.SizeFrom = fieldLengthFrom
- }
-
- return f, nil
-}
-
-// parseService parses VPP binary API service object from JSON node
-func parseService(ctx *context, svcName string, svcNode *jsongo.Node) (*Service, error) {
- if svcNode.Len() == 0 || svcNode.At(replyField).GetType() != jsongo.TypeValue {
- return nil, errors.New("invalid JSON for service specified")
- }
-
- svc := Service{
- Name: svcName,
- RequestType: svcName,
- }
-
- 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 != serviceNoReply {
- svc.ReplyType = reply
- }
- }
-
- // stream service (dumps)
- if streamNode := svcNode.At(streamField); streamNode.GetType() == jsongo.TypeValue {
- var ok bool
- svc.Stream, ok = streamNode.Get().(bool)
- if !ok {
- return nil, fmt.Errorf("service stream is %T, not a string", streamNode.Get())
- }
- }
-
- // events service (event subscription)
- 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)
- }
- }
-
- // validate service
- if len(svc.Events) > 0 {
- // EVENT service
- if !strings.HasPrefix(svc.RequestType, serviceEventPrefix) {
- logrus.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) {
- logrus.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) {
- logrus.Debugf("unusual REQUEST service: %+v\n"+
- "- service %q does not have %q suffix in reply.",
- svc, svc.Name, serviceReplySuffix)
- }
- }
-
- return &svc, nil
-}