mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-23 03:18:59 +00:00
Slightly clean up XDR generator
This commit is contained in:
parent
a6d67d30f5
commit
2d4b89a8e9
@ -19,21 +19,30 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
var output string
|
type fieldInfo struct {
|
||||||
|
|
||||||
type field struct {
|
|
||||||
Name string
|
Name string
|
||||||
IsBasic bool
|
IsBasic bool // handled by one the native Read/WriteUint64 etc functions
|
||||||
IsSlice bool
|
IsSlice bool // field is a slice of FieldType
|
||||||
IsMap bool
|
FieldType string // original type of field, i.e. "int"
|
||||||
FieldType string
|
Encoder string // the encoder name, i.e. "Uint64" for Read/WriteUint64
|
||||||
KeyType string
|
Convert string // what to convert to when encoding, i.e. "uint64"
|
||||||
Encoder string
|
Max int // max size for slices and strings
|
||||||
Convert string
|
|
||||||
Max int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var headerTpl = template.Must(template.New("header").Parse(`package {{.Package}}
|
type structInfo struct {
|
||||||
|
Name string
|
||||||
|
Fields []fieldInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
var headerTpl = template.Must(template.New("header").Parse(`// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
|
||||||
|
// All rights reserved. Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// ************************************************************
|
||||||
|
// This file is automatically generated by genxdr. Do not edit.
|
||||||
|
// ************************************************************
|
||||||
|
|
||||||
|
package {{.Package}}
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -61,34 +70,34 @@ func (o {{.TypeName}}) AppendXDR(bs []byte) []byte {
|
|||||||
}//+n
|
}//+n
|
||||||
|
|
||||||
func (o {{.TypeName}}) encodeXDR(xw *xdr.Writer) (int, error) {
|
func (o {{.TypeName}}) encodeXDR(xw *xdr.Writer) (int, error) {
|
||||||
{{range $field := .Fields}}
|
{{range $fieldInfo := .Fields}}
|
||||||
{{if not $field.IsSlice}}
|
{{if not $fieldInfo.IsSlice}}
|
||||||
{{if ne $field.Convert ""}}
|
{{if ne $fieldInfo.Convert ""}}
|
||||||
xw.Write{{$field.Encoder}}({{$field.Convert}}(o.{{$field.Name}}))
|
xw.Write{{$fieldInfo.Encoder}}({{$fieldInfo.Convert}}(o.{{$fieldInfo.Name}}))
|
||||||
{{else if $field.IsBasic}}
|
{{else if $fieldInfo.IsBasic}}
|
||||||
{{if ge $field.Max 1}}
|
{{if ge $fieldInfo.Max 1}}
|
||||||
if len(o.{{$field.Name}}) > {{$field.Max}} {
|
if len(o.{{$fieldInfo.Name}}) > {{$fieldInfo.Max}} {
|
||||||
return xw.Tot(), xdr.ErrElementSizeExceeded
|
return xw.Tot(), xdr.ErrElementSizeExceeded
|
||||||
}
|
}
|
||||||
{{end}}
|
{{end}}
|
||||||
xw.Write{{$field.Encoder}}(o.{{$field.Name}})
|
xw.Write{{$fieldInfo.Encoder}}(o.{{$fieldInfo.Name}})
|
||||||
{{else}}
|
{{else}}
|
||||||
o.{{$field.Name}}.encodeXDR(xw)
|
o.{{$fieldInfo.Name}}.encodeXDR(xw)
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{if ge $field.Max 1}}
|
{{if ge $fieldInfo.Max 1}}
|
||||||
if len(o.{{$field.Name}}) > {{$field.Max}} {
|
if len(o.{{$fieldInfo.Name}}) > {{$fieldInfo.Max}} {
|
||||||
return xw.Tot(), xdr.ErrElementSizeExceeded
|
return xw.Tot(), xdr.ErrElementSizeExceeded
|
||||||
}
|
}
|
||||||
{{end}}
|
{{end}}
|
||||||
xw.WriteUint32(uint32(len(o.{{$field.Name}})))
|
xw.WriteUint32(uint32(len(o.{{$fieldInfo.Name}})))
|
||||||
for i := range o.{{$field.Name}} {
|
for i := range o.{{$fieldInfo.Name}} {
|
||||||
{{if ne $field.Convert ""}}
|
{{if ne $fieldInfo.Convert ""}}
|
||||||
xw.Write{{$field.Encoder}}({{$field.Convert}}(o.{{$field.Name}}[i]))
|
xw.Write{{$fieldInfo.Encoder}}({{$fieldInfo.Convert}}(o.{{$fieldInfo.Name}}[i]))
|
||||||
{{else if $field.IsBasic}}
|
{{else if $fieldInfo.IsBasic}}
|
||||||
xw.Write{{$field.Encoder}}(o.{{$field.Name}}[i])
|
xw.Write{{$fieldInfo.Encoder}}(o.{{$fieldInfo.Name}}[i])
|
||||||
{{else}}
|
{{else}}
|
||||||
o.{{$field.Name}}[i].encodeXDR(xw)
|
o.{{$fieldInfo.Name}}[i].encodeXDR(xw)
|
||||||
{{end}}
|
{{end}}
|
||||||
}
|
}
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -108,34 +117,34 @@ func (o *{{.TypeName}}) UnmarshalXDR(bs []byte) error {
|
|||||||
}//+n
|
}//+n
|
||||||
|
|
||||||
func (o *{{.TypeName}}) decodeXDR(xr *xdr.Reader) error {
|
func (o *{{.TypeName}}) decodeXDR(xr *xdr.Reader) error {
|
||||||
{{range $field := .Fields}}
|
{{range $fieldInfo := .Fields}}
|
||||||
{{if not $field.IsSlice}}
|
{{if not $fieldInfo.IsSlice}}
|
||||||
{{if ne $field.Convert ""}}
|
{{if ne $fieldInfo.Convert ""}}
|
||||||
o.{{$field.Name}} = {{$field.FieldType}}(xr.Read{{$field.Encoder}}())
|
o.{{$fieldInfo.Name}} = {{$fieldInfo.FieldType}}(xr.Read{{$fieldInfo.Encoder}}())
|
||||||
{{else if $field.IsBasic}}
|
{{else if $fieldInfo.IsBasic}}
|
||||||
{{if ge $field.Max 1}}
|
{{if ge $fieldInfo.Max 1}}
|
||||||
o.{{$field.Name}} = xr.Read{{$field.Encoder}}Max({{$field.Max}})
|
o.{{$fieldInfo.Name}} = xr.Read{{$fieldInfo.Encoder}}Max({{$fieldInfo.Max}})
|
||||||
{{else}}
|
{{else}}
|
||||||
o.{{$field.Name}} = xr.Read{{$field.Encoder}}()
|
o.{{$fieldInfo.Name}} = xr.Read{{$fieldInfo.Encoder}}()
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
(&o.{{$field.Name}}).decodeXDR(xr)
|
(&o.{{$fieldInfo.Name}}).decodeXDR(xr)
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
_{{$field.Name}}Size := int(xr.ReadUint32())
|
_{{$fieldInfo.Name}}Size := int(xr.ReadUint32())
|
||||||
{{if ge $field.Max 1}}
|
{{if ge $fieldInfo.Max 1}}
|
||||||
if _{{$field.Name}}Size > {{$field.Max}} {
|
if _{{$fieldInfo.Name}}Size > {{$fieldInfo.Max}} {
|
||||||
return xdr.ErrElementSizeExceeded
|
return xdr.ErrElementSizeExceeded
|
||||||
}
|
}
|
||||||
{{end}}
|
{{end}}
|
||||||
o.{{$field.Name}} = make([]{{$field.FieldType}}, _{{$field.Name}}Size)
|
o.{{$fieldInfo.Name}} = make([]{{$fieldInfo.FieldType}}, _{{$fieldInfo.Name}}Size)
|
||||||
for i := range o.{{$field.Name}} {
|
for i := range o.{{$fieldInfo.Name}} {
|
||||||
{{if ne $field.Convert ""}}
|
{{if ne $fieldInfo.Convert ""}}
|
||||||
o.{{$field.Name}}[i] = {{$field.FieldType}}(xr.Read{{$field.Encoder}}())
|
o.{{$fieldInfo.Name}}[i] = {{$fieldInfo.FieldType}}(xr.Read{{$fieldInfo.Encoder}}())
|
||||||
{{else if $field.IsBasic}}
|
{{else if $fieldInfo.IsBasic}}
|
||||||
o.{{$field.Name}}[i] = xr.Read{{$field.Encoder}}()
|
o.{{$fieldInfo.Name}}[i] = xr.Read{{$fieldInfo.Encoder}}()
|
||||||
{{else}}
|
{{else}}
|
||||||
(&o.{{$field.Name}}[i]).decodeXDR(xr)
|
(&o.{{$fieldInfo.Name}}[i]).decodeXDR(xr)
|
||||||
{{end}}
|
{{end}}
|
||||||
}
|
}
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -163,8 +172,9 @@ var xdrEncoders = map[string]typeSet{
|
|||||||
"bool": typeSet{"", "Bool"},
|
"bool": typeSet{"", "Bool"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleStruct(name string, t *ast.StructType) {
|
func handleStruct(t *ast.StructType) []fieldInfo {
|
||||||
var fs []field
|
var fs []fieldInfo
|
||||||
|
|
||||||
for _, sf := range t.Fields.List {
|
for _, sf := range t.Fields.List {
|
||||||
if len(sf.Names) == 0 {
|
if len(sf.Names) == 0 {
|
||||||
// We don't handle anonymous fields
|
// We don't handle anonymous fields
|
||||||
@ -183,12 +193,12 @@ func handleStruct(name string, t *ast.StructType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var f field
|
var f fieldInfo
|
||||||
switch ft := sf.Type.(type) {
|
switch ft := sf.Type.(type) {
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
tn := ft.Name
|
tn := ft.Name
|
||||||
if enc, ok := xdrEncoders[tn]; ok {
|
if enc, ok := xdrEncoders[tn]; ok {
|
||||||
f = field{
|
f = fieldInfo{
|
||||||
Name: fn,
|
Name: fn,
|
||||||
IsBasic: true,
|
IsBasic: true,
|
||||||
FieldType: tn,
|
FieldType: tn,
|
||||||
@ -197,7 +207,7 @@ func handleStruct(name string, t *ast.StructType) {
|
|||||||
Max: max,
|
Max: max,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
f = field{
|
f = fieldInfo{
|
||||||
Name: fn,
|
Name: fn,
|
||||||
IsBasic: false,
|
IsBasic: false,
|
||||||
FieldType: tn,
|
FieldType: tn,
|
||||||
@ -213,7 +223,7 @@ func handleStruct(name string, t *ast.StructType) {
|
|||||||
|
|
||||||
tn := ft.Elt.(*ast.Ident).Name
|
tn := ft.Elt.(*ast.Ident).Name
|
||||||
if enc, ok := xdrEncoders["[]"+tn]; ok {
|
if enc, ok := xdrEncoders["[]"+tn]; ok {
|
||||||
f = field{
|
f = fieldInfo{
|
||||||
Name: fn,
|
Name: fn,
|
||||||
IsBasic: true,
|
IsBasic: true,
|
||||||
FieldType: tn,
|
FieldType: tn,
|
||||||
@ -222,7 +232,7 @@ func handleStruct(name string, t *ast.StructType) {
|
|||||||
Max: max,
|
Max: max,
|
||||||
}
|
}
|
||||||
} else if enc, ok := xdrEncoders[tn]; ok {
|
} else if enc, ok := xdrEncoders[tn]; ok {
|
||||||
f = field{
|
f = fieldInfo{
|
||||||
Name: fn,
|
Name: fn,
|
||||||
IsBasic: true,
|
IsBasic: true,
|
||||||
IsSlice: true,
|
IsSlice: true,
|
||||||
@ -232,7 +242,7 @@ func handleStruct(name string, t *ast.StructType) {
|
|||||||
Max: max,
|
Max: max,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
f = field{
|
f = fieldInfo{
|
||||||
Name: fn,
|
Name: fn,
|
||||||
IsBasic: false,
|
IsBasic: false,
|
||||||
IsSlice: true,
|
IsSlice: true,
|
||||||
@ -245,17 +255,13 @@ func handleStruct(name string, t *ast.StructType) {
|
|||||||
fs = append(fs, f)
|
fs = append(fs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch output {
|
return fs
|
||||||
case "code":
|
|
||||||
generateCode(name, fs)
|
|
||||||
case "diagram":
|
|
||||||
generateDiagram(name, fs)
|
|
||||||
case "xdr":
|
|
||||||
generateXdr(name, fs)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateCode(name string, fs []field) {
|
func generateCode(s structInfo) {
|
||||||
|
name := s.Name
|
||||||
|
fs := s.Fields
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err := encodeTpl.Execute(&buf, map[string]interface{}{"TypeName": name, "Fields": fs})
|
err := encodeTpl.Execute(&buf, map[string]interface{}{"TypeName": name, "Fields": fs})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -272,7 +278,16 @@ func generateCode(name string, fs []field) {
|
|||||||
fmt.Println(string(bs))
|
fmt.Println(string(bs))
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateDiagram(sn string, fs []field) {
|
func uncamelize(s string) string {
|
||||||
|
return regexp.MustCompile("[a-z][A-Z]").ReplaceAllStringFunc(s, func(camel string) string {
|
||||||
|
return camel[:1] + " " + camel[1:]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateDiagram(s structInfo) {
|
||||||
|
sn := s.Name
|
||||||
|
fs := s.Fields
|
||||||
|
|
||||||
fmt.Println(sn + " Structure:")
|
fmt.Println(sn + " Structure:")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println(" 0 1 2 3")
|
fmt.Println(" 0 1 2 3")
|
||||||
@ -283,28 +298,32 @@ func generateDiagram(sn string, fs []field) {
|
|||||||
for _, f := range fs {
|
for _, f := range fs {
|
||||||
tn := f.FieldType
|
tn := f.FieldType
|
||||||
sl := f.IsSlice
|
sl := f.IsSlice
|
||||||
|
name := uncamelize(f.Name)
|
||||||
|
|
||||||
if sl {
|
if sl {
|
||||||
fmt.Printf("| %s |\n", center("Number of "+f.Name, 61))
|
fmt.Printf("| %s |\n", center("Number of "+name, 61))
|
||||||
fmt.Println(line)
|
fmt.Println(line)
|
||||||
}
|
}
|
||||||
switch tn {
|
switch tn {
|
||||||
|
case "bool":
|
||||||
|
fmt.Printf("| %s |V|\n", center(name+" (V=0 or 1)", 59))
|
||||||
|
fmt.Println(line)
|
||||||
case "uint16":
|
case "uint16":
|
||||||
fmt.Printf("| %s | %s |\n", center(f.Name, 29), center("0x0000", 29))
|
fmt.Printf("| %s | %s |\n", center("0x0000", 29), center(name, 29))
|
||||||
fmt.Println(line)
|
fmt.Println(line)
|
||||||
case "uint32":
|
case "uint32":
|
||||||
fmt.Printf("| %s |\n", center(f.Name, 61))
|
fmt.Printf("| %s |\n", center(name, 61))
|
||||||
fmt.Println(line)
|
fmt.Println(line)
|
||||||
case "int64", "uint64":
|
case "int64", "uint64":
|
||||||
fmt.Printf("| %-61s |\n", "")
|
fmt.Printf("| %-61s |\n", "")
|
||||||
fmt.Printf("+ %s +\n", center(f.Name+" (64 bits)", 61))
|
fmt.Printf("+ %s +\n", center(name+" (64 bits)", 61))
|
||||||
fmt.Printf("| %-61s |\n", "")
|
fmt.Printf("| %-61s |\n", "")
|
||||||
fmt.Println(line)
|
fmt.Println(line)
|
||||||
case "string", "byte": // XXX We assume slice of byte!
|
case "string", "byte": // XXX We assume slice of byte!
|
||||||
fmt.Printf("| %s |\n", center("Length of "+f.Name, 61))
|
fmt.Printf("| %s |\n", center("Length of "+name, 61))
|
||||||
fmt.Println(line)
|
fmt.Println(line)
|
||||||
fmt.Printf("/ %61s /\n", "")
|
fmt.Printf("/ %61s /\n", "")
|
||||||
fmt.Printf("\\ %s \\\n", center(f.Name+" (variable length)", 61))
|
fmt.Printf("\\ %s \\\n", center(name+" (variable length)", 61))
|
||||||
fmt.Printf("/ %61s /\n", "")
|
fmt.Printf("/ %61s /\n", "")
|
||||||
fmt.Println(line)
|
fmt.Println(line)
|
||||||
default:
|
default:
|
||||||
@ -323,30 +342,35 @@ func generateDiagram(sn string, fs []field) {
|
|||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateXdr(sn string, fs []field) {
|
func generateXdr(s structInfo) {
|
||||||
|
sn := s.Name
|
||||||
|
fs := s.Fields
|
||||||
|
|
||||||
fmt.Printf("struct %s {\n", sn)
|
fmt.Printf("struct %s {\n", sn)
|
||||||
|
|
||||||
for _, f := range fs {
|
for _, f := range fs {
|
||||||
tn := f.FieldType
|
tn := f.FieldType
|
||||||
fn := f.Name
|
fn := f.Name
|
||||||
suf := ""
|
suf := ""
|
||||||
|
l := ""
|
||||||
|
if f.Max > 0 {
|
||||||
|
l = strconv.Itoa(f.Max)
|
||||||
|
}
|
||||||
if f.IsSlice {
|
if f.IsSlice {
|
||||||
suf = "<>"
|
suf = "<" + l + ">"
|
||||||
}
|
}
|
||||||
|
|
||||||
switch tn {
|
switch tn {
|
||||||
case "uint16":
|
case "uint16", "uint32":
|
||||||
fmt.Printf("\tunsigned short %s%s;\n", fn, suf)
|
|
||||||
case "uint32":
|
|
||||||
fmt.Printf("\tunsigned int %s%s;\n", fn, suf)
|
fmt.Printf("\tunsigned int %s%s;\n", fn, suf)
|
||||||
case "int64":
|
case "int64":
|
||||||
fmt.Printf("\thyper %s%s;\n", fn, suf)
|
fmt.Printf("\thyper %s%s;\n", fn, suf)
|
||||||
case "uint64":
|
case "uint64":
|
||||||
fmt.Printf("\tunsigned hyper %s%s;\n", fn, suf)
|
fmt.Printf("\tunsigned hyper %s%s;\n", fn, suf)
|
||||||
case "string":
|
case "string":
|
||||||
fmt.Printf("\tstring %s<>;\n", fn)
|
fmt.Printf("\tstring %s<%s>;\n", fn, l)
|
||||||
case "byte":
|
case "byte":
|
||||||
fmt.Printf("\topaque %s<>;\n", fn)
|
fmt.Printf("\topaque %s<%s>;\n", fn, l)
|
||||||
default:
|
default:
|
||||||
fmt.Printf("\t%s %s%s;\n", tn, fn, suf)
|
fmt.Printf("\t%s %s%s;\n", tn, fn, suf)
|
||||||
}
|
}
|
||||||
@ -365,14 +389,15 @@ func center(s string, w int) string {
|
|||||||
return strings.Repeat(" ", l) + s + strings.Repeat(" ", r)
|
return strings.Repeat(" ", l) + s + strings.Repeat(" ", r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func inspector(fset *token.FileSet) func(ast.Node) bool {
|
func inspector(structs *[]structInfo) func(ast.Node) bool {
|
||||||
return func(n ast.Node) bool {
|
return func(n ast.Node) bool {
|
||||||
switch n := n.(type) {
|
switch n := n.(type) {
|
||||||
case *ast.TypeSpec:
|
case *ast.TypeSpec:
|
||||||
switch t := n.Type.(type) {
|
switch t := n.Type.(type) {
|
||||||
case *ast.StructType:
|
case *ast.StructType:
|
||||||
name := n.Name.Name
|
name := n.Name.Name
|
||||||
handleStruct(name, t)
|
fs := handleStruct(t)
|
||||||
|
*structs = append(*structs, structInfo{name, fs})
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
default:
|
default:
|
||||||
@ -382,23 +407,25 @@ func inspector(fset *token.FileSet) func(ast.Node) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.StringVar(&output, "output", "code", "code,xdr,diagram")
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
fname := flag.Arg(0)
|
fname := flag.Arg(0)
|
||||||
|
|
||||||
// Create the AST by parsing src.
|
fset := token.NewFileSet()
|
||||||
fset := token.NewFileSet() // positions are relative to fset
|
|
||||||
f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)
|
f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//ast.Print(fset, f)
|
var structs []structInfo
|
||||||
|
i := inspector(&structs)
|
||||||
if output == "code" {
|
|
||||||
headerTpl.Execute(os.Stdout, map[string]string{"Package": f.Name.Name})
|
|
||||||
}
|
|
||||||
|
|
||||||
i := inspector(fset)
|
|
||||||
ast.Inspect(f, i)
|
ast.Inspect(f, i)
|
||||||
|
|
||||||
|
headerTpl.Execute(os.Stdout, map[string]string{"Package": f.Name.Name})
|
||||||
|
for _, s := range structs {
|
||||||
|
fmt.Printf("\n/*\n\n")
|
||||||
|
generateDiagram(s)
|
||||||
|
generateXdr(s)
|
||||||
|
fmt.Printf("*/\n")
|
||||||
|
generateCode(s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user