Parse proc annotations and store in Proc struct

This commit is contained in:
Yuriy Taraday 2018-02-26 00:53:33 +04:00
parent 5d8cdfc854
commit 3613b30fe2
3 changed files with 118 additions and 15 deletions

View File

@ -159,13 +159,41 @@ type Case struct {
// Proc holds information about a libvirt procedure the parser has found. // Proc holds information about a libvirt procedure the parser has found.
type Proc struct { type Proc struct {
Num int64 // The libvirt procedure number. Num int64 // The libvirt procedure number.
Name string // The name of the go func. Name string // The name of the go func.
LVName string // The name of the libvirt proc this wraps. LVName string // The name of the libvirt proc this wraps.
Args []Decl // The contents of the args struct for this procedure. Args []Decl // The contents of the args struct for this procedure.
Ret []Decl // The contents of the ret struct for this procedure. Ret []Decl // The contents of the ret struct for this procedure.
ArgsStruct string // The name of the args struct for this procedure. ArgsStruct string // The name of the args struct for this procedure.
RetStruct string // The name of the ret struct for this procedure. RetStruct string // The name of the ret struct for this procedure.
ReadStreamIdx int // The index of read stream in function argument list
WriteStreamIdx int // The index of read stream in function argument list
}
type ProcMetaGenerate int
const (
ProcMetaGenerateNone ProcMetaGenerate = iota
ProcMetaGenerateClient
ProcMetaGenerateServer
ProcMetaGenerateBoth
)
type ProcMetaPriority int
const (
ProcMetaPriorityLow ProcMetaPriority = iota
ProcMetaPriorityHigh
)
// ProcMeta holds information from annotations attached to a libvirt procedure
type ProcMeta struct {
Generate ProcMetaGenerate
ReadStream int
WriteStream int
Priority ProcMetaPriority
Acls []string
Aclfilter string
} }
type structStack []*Structure type structStack []*Structure
@ -552,7 +580,20 @@ func AddEnumVal(name, val string) error {
if err != nil { if err != nil {
return fmt.Errorf("invalid enum value %v = %v", name, val) return fmt.Errorf("invalid enum value %v = %v", name, val)
} }
return addEnumVal(name, ev) return addEnumVal(name, ev, nil)
}
// AddEnumValMeta will add a new enum value with attached metadata to the list.
func AddEnumValMeta(name, val, meta string) error {
ev, err := parseNumber(val)
if err != nil {
return fmt.Errorf("invalid enum value %v = %v", name, val)
}
metaObj, err := parseMeta(meta)
if err != nil {
return fmt.Errorf("invalid metadata for enum value %v: %v", name, err)
}
return addEnumVal(name, ev, metaObj)
} }
// AddEnumAutoVal adds an enum to the list, using the automatically-incremented // AddEnumAutoVal adds an enum to the list, using the automatically-incremented
@ -560,14 +601,14 @@ func AddEnumVal(name, val string) error {
// explicit value. // explicit value.
func AddEnumAutoVal(name string) error { func AddEnumAutoVal(name string) error {
CurrentEnumVal++ CurrentEnumVal++
return addEnumVal(name, CurrentEnumVal) return addEnumVal(name, CurrentEnumVal, nil)
} }
func addEnumVal(name string, val int64) error { func addEnumVal(name string, val int64, meta *ProcMeta) error {
goname := constNameTransform(name) goname := constNameTransform(name)
Gen.EnumVals = append(Gen.EnumVals, ConstItem{goname, name, fmt.Sprintf("%d", val)}) Gen.EnumVals = append(Gen.EnumVals, ConstItem{goname, name, fmt.Sprintf("%d", val)})
CurrentEnumVal = val CurrentEnumVal = val
addProc(goname, name, val) addProc(goname, name, val, meta)
return nil return nil
} }
@ -584,12 +625,16 @@ func AddConst(name, val string) error {
// addProc checks an enum value to see if it's a procedure number. If so, we // addProc checks an enum value to see if it's a procedure number. If so, we
// add the procedure to our list for later generation. // add the procedure to our list for later generation.
func addProc(goname, lvname string, val int64) { func addProc(goname, lvname string, val int64, meta *ProcMeta) {
if !strings.HasPrefix(goname, "Proc") { if !strings.HasPrefix(goname, "Proc") {
return return
} }
goname = goname[4:] goname = goname[4:]
proc := &Proc{Num: val, Name: goname, LVName: lvname} proc := &Proc{Num: val, Name: goname, LVName: lvname, ReadStreamIdx: -1, WriteStreamIdx: -1}
if meta != nil {
proc.ReadStreamIdx = meta.ReadStream
proc.WriteStreamIdx = meta.WriteStream
}
Gen.Procs = append(Gen.Procs, *proc) Gen.Procs = append(Gen.Procs, *proc)
} }
@ -605,6 +650,64 @@ func parseNumber(val string) (int64, error) {
return n, err return n, err
} }
// parseMeta parses procedure metadata to simple string mapping
func parseMeta(meta string) (*ProcMeta, error) {
res := &ProcMeta{
ReadStream: -1,
WriteStream: -1,
}
for _, line := range strings.Split(meta, "\n") {
atInd := strings.Index(line, "@")
if atInd == -1 {
// Should be only first and last line of comment
continue
}
spl := strings.SplitN(line[atInd+1:], ":", 2)
if len(spl) != 2 {
return nil, fmt.Errorf("invalid annotation: %s", meta)
}
spl[1] = strings.Trim(spl[1], " ")
if spl[0] == "generate" {
if spl[1] == "none" {
res.Generate = ProcMetaGenerateNone
} else if spl[1] == "client" {
res.Generate = ProcMetaGenerateClient
} else if spl[1] == "server" {
res.Generate = ProcMetaGenerateServer
} else if spl[1] == "both" {
res.Generate = ProcMetaGenerateBoth
} else {
return nil, fmt.Errorf("invalid value for generate: %s", spl[1])
}
} else if spl[0] == "readstream" {
var err error
res.ReadStream, err = strconv.Atoi(spl[1])
if err != nil {
return nil, fmt.Errorf("invalid value for readstread: %s", spl[1])
}
} else if spl[0] == "writestream" {
var err error
res.WriteStream, err = strconv.Atoi(spl[1])
if err != nil {
return nil, fmt.Errorf("invalid value for readstread: %s", spl[1])
}
} else if spl[0] == "priority" {
if spl[1] == "low" {
res.Priority = ProcMetaPriorityLow
} else if spl[1] == "high" {
res.Priority = ProcMetaPriorityHigh
} else {
return nil, fmt.Errorf("invalid value for priority: %s", spl[1])
}
} else if spl[0] == "acl" {
res.Acls = append(res.Acls, spl[1])
} else if spl[0] == "aclfilter" {
res.Aclfilter = spl[1]
}
}
return res, nil
}
// StartStruct is called from the parser when a struct definition is found, but // StartStruct is called from the parser when a struct definition is found, but
// before the member declarations are processed. // before the member declarations are processed.
func StartStruct(name string) { func StartStruct(name string) {

View File

@ -101,7 +101,7 @@ enum_value
} }
} }
| METADATACOMMENT enum_value_ident '=' value { | METADATACOMMENT enum_value_ident '=' value {
err := AddEnumVal($2.val, $4.val) err := AddEnumValMeta($2.val, $4.val, $1.val)
if err != nil { if err != nil {
yylex.Error(err.Error()) yylex.Error(err.Error())
return 1 return 1

View File

@ -606,7 +606,7 @@ yydefault:
yyDollar = yyS[yypt-4 : yypt+1] yyDollar = yyS[yypt-4 : yypt+1]
//line sunrpc.y:103 //line sunrpc.y:103
{ {
err := AddEnumVal(yyDollar[2].val, yyDollar[4].val) err := AddEnumValMeta(yyDollar[2].val, yyDollar[4].val, yyDollar[1].val)
if err != nil { if err != nil {
yylex.Error(err.Error()) yylex.Error(err.Error())
return 1 return 1