import (
"fmt"
"path"
+ "strconv"
"strings"
"git.fd.io/govpp.git/binapigen/vppapi"
}
for _, enumType := range apifile.EnumTypes {
- file.Enums = append(file.Enums, newEnum(gen, file, enumType))
+ file.Enums = append(file.Enums, newEnum(gen, file, enumType, false))
+ }
+ for _, enumflagType := range apifile.EnumflagTypes {
+ file.Enums = append(file.Enums, newEnum(gen, file, enumflagType, true))
}
for _, aliasType := range apifile.AliasTypes {
file.Aliases = append(file.Aliases, newAlias(gen, file, aliasType))
return false
}
-func normalizeImport(imp string) string {
- imp = path.Base(imp)
- if idx := strings.Index(imp, "."); idx >= 0 {
- imp = imp[:idx]
- }
- return imp
-}
-
const (
enumFlagSuffix = "_flags"
)
vppapi.EnumType
GoIdent
+
+ IsFlag bool
}
-func newEnum(gen *Generator, file *File, apitype vppapi.EnumType) *Enum {
+func newEnum(gen *Generator, file *File, apitype vppapi.EnumType, isFlag bool) *Enum {
typ := &Enum{
EnumType: apitype,
GoIdent: GoIdent{
GoName: camelCaseName(apitype.Name),
GoImportPath: file.GoImportPath,
},
+ IsFlag: isFlag,
}
gen.enumsByName[typ.Name] = typ
return typ
},
}
gen.structsByName[typ.Name] = typ
- for _, fieldType := range apitype.Fields {
- field := newField(gen, file, fieldType)
- field.ParentStruct = typ
+ for i, fieldType := range apitype.Fields {
+ field := newField(gen, file, typ, fieldType, i)
typ.Fields = append(typ.Fields, field)
}
return typ
typ := &Union{
UnionType: apitype,
GoIdent: GoIdent{
- GoName: camelCaseName(apitype.Name),
+ GoName: withSuffix(camelCaseName(apitype.Name), "Union"),
GoImportPath: file.GoImportPath,
},
}
gen.unionsByName[typ.Name] = typ
- for _, fieldType := range apitype.Fields {
- field := newField(gen, file, fieldType)
- field.ParentUnion = typ
+ for i, fieldType := range apitype.Fields {
+ field := newField(gen, file, typ, fieldType, i)
typ.Fields = append(typ.Fields, field)
}
return typ
msgTypeEvent // msg_id, client_index
)
-func apiMsgType(t msgType) GoIdent {
- switch t {
- case msgTypeRequest:
- return govppApiPkg.Ident("RequestMessage")
- case msgTypeReply:
- return govppApiPkg.Ident("ReplyMessage")
- case msgTypeEvent:
- return govppApiPkg.Ident("EventMessage")
- default:
- return govppApiPkg.Ident("OtherMessage")
- }
-}
-
-// message fields
+// common message fields
const (
fieldMsgID = "_vl_msg_id"
fieldClientIndex = "client_index"
GoIdent: newGoIdent(file, apitype.Name),
}
gen.messagesByName[apitype.Name] = msg
- n := 0
+ var n int
for _, fieldType := range apitype.Fields {
- // skip internal fields
- switch strings.ToLower(fieldType.Name) {
- case fieldMsgID:
- continue
- case fieldClientIndex, fieldContext:
- if n == 0 {
+ if n == 0 {
+ // skip header fields
+ switch strings.ToLower(fieldType.Name) {
+ case fieldMsgID, fieldClientIndex, fieldContext:
continue
}
}
n++
- field := newField(gen, file, fieldType)
- field.ParentMessage = msg
+ field := newField(gen, file, msg, fieldType, n)
msg.Fields = append(msg.Fields, field)
}
return msg
func getMsgType(m vppapi.Message) (msgType, error) {
if len(m.Fields) == 0 {
- return msgType(0), fmt.Errorf("message %s has no fields", m.Name)
+ return msgType(-1), fmt.Errorf("message %s has no fields", m.Name)
}
- typ := msgTypeBase
- wasClientIndex := false
+ var typ msgType
+ var wasClientIndex bool
for i, field := range m.Fields {
- if i == 0 {
+ switch i {
+ case 0:
if field.Name != fieldMsgID {
- return msgType(0), fmt.Errorf("message %s is missing ID field", m.Name)
+ return msgType(-1), fmt.Errorf("message %s is missing ID field", m.Name)
}
- } else if i == 1 {
+ case 1:
if field.Name == fieldClientIndex {
// "client_index" as the second member,
// this might be an event message or a request
// reply needs "context" as the second member
typ = msgTypeReply
}
- } else if i == 2 {
- if wasClientIndex && field.Name == fieldContext {
+ case 2:
+ if field.Name == fieldContext && wasClientIndex {
// request needs "client_index" as the second member
// and "context" as the third member
typ = msgTypeRequest
return typ, nil
}
+func getRetvalField(m *Message) *Field {
+ for _, field := range m.Fields {
+ if field.Name == fieldRetval {
+ return field
+ }
+ }
+ return nil
+}
+
+// Field represents a field for message or struct/union types.
type Field struct {
vppapi.Field
GoName string
+ // Index defines field index in parent.
+ Index int
+
+ // DefaultValue is a default value of field or
+ // nil if default value is not defined for field.
DefaultValue interface{}
- // Reference to actual type of this field
+ // Reference to actual type of this field.
+ //
+ // For fields with built-in types all of these are nil,
+ // otherwise only one is set to non-nil value.
TypeEnum *Enum
TypeAlias *Alias
TypeStruct *Struct
TypeUnion *Union
- // Parent in which this field is declared
+ // Parent in which this field is declared.
ParentMessage *Message
ParentStruct *Struct
ParentUnion *Union
- // Field reference for fields determining size
+ // Field reference for fields with variable size.
FieldSizeOf *Field
FieldSizeFrom *Field
}
-func newField(gen *Generator, file *File, apitype vppapi.Field) *Field {
+func newField(gen *Generator, file *File, parent interface{}, apitype vppapi.Field, index int) *Field {
typ := &Field{
Field: apitype,
GoName: camelCaseName(apitype.Name),
+ Index: index,
+ }
+ switch p := parent.(type) {
+ case *Message:
+ typ.ParentMessage = p
+ case *Struct:
+ typ.ParentStruct = p
+ case *Union:
+ typ.ParentUnion = p
+ default:
+ panic(fmt.Sprintf("invalid field parent: %T", parent))
}
if apitype.Meta != nil {
if val, ok := apitype.Meta[optFieldDefault]; ok {
}
return nil
}
+
+// GoIdent is a Go identifier, consisting of a name and import path.
+// The name is a single identifier and may not be a dot-qualified selector.
+type GoIdent struct {
+ GoName string
+ GoImportPath GoImportPath
+}
+
+func (id GoIdent) String() string {
+ return fmt.Sprintf("%q.%v", id.GoImportPath, id.GoName)
+}
+
+func newGoIdent(f *File, fullName string) GoIdent {
+ name := strings.TrimPrefix(fullName, string(f.PackageName)+".")
+ return GoIdent{
+ GoName: camelCaseName(name),
+ GoImportPath: f.GoImportPath,
+ }
+}
+
+// GoImportPath is a Go import path for a package.
+type GoImportPath string
+
+func (p GoImportPath) String() string {
+ return strconv.Quote(string(p))
+}
+
+func (p GoImportPath) Ident(s string) GoIdent {
+ return GoIdent{GoName: s, GoImportPath: p}
+}
+
+type GoPackageName string
+
+func cleanPackageName(name string) GoPackageName {
+ return GoPackageName(sanitizedName(name))
+}
+
+// baseName returns the last path element of the name, with the last dotted suffix removed.
+func baseName(name string) string {
+ // First, find the last element
+ if i := strings.LastIndex(name, "/"); i >= 0 {
+ name = name[i+1:]
+ }
+ // Now drop the suffix
+ if i := strings.LastIndex(name, "."); i >= 0 {
+ name = name[:i]
+ }
+ return name
+}
+
+// normalizeImport returns the last path element of the import, with all dotted suffixes removed.
+func normalizeImport(imp string) string {
+ imp = path.Base(imp)
+ if idx := strings.Index(imp, "."); idx >= 0 {
+ imp = imp[:idx]
+ }
+ return imp
+}