package main import ( "bytes" "go/ast" "go/format" "go/parser" "go/token" "os" "sort" "strconv" "text/template" ) const codeTemplate = `// Code generated by internal/generator/c2c_switcher DO NOT EDIT. package client import ( {{range .Imports}} {{.}} {{end}} ) const ( UnknownDecoder = iota {{range .Consts}} {{.}} {{end}} ) func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, *network.IncomingPacketInfo), decoderType uint8) { switch msgType { {{range .Decoders}} case {{.Id}}: return {{.Func}}, {{.DecoderType}} {{end}} default: return nil, UnknownDecoder } }` type decoder struct { Id int64 Func string DecoderType string } type DecoderSort []decoder func (d DecoderSort) Len() int { return len(d) } func (d DecoderSort) Swap(i, j int) { d[i], d[j] = d[j], d[i] } func (d DecoderSort) Less(i, j int) bool { return d[i].Id < d[j].Id } func main() { type switchFile struct { Imports []string Consts []string Decoders DecoderSort } var sf switchFile fset := token.NewFileSet() astF, err := parser.ParseFile(fset, "_c2c_decoders.go", nil, parser.AllErrors|parser.ParseComments) if err != nil { panic(err) } sf.Imports = make([]string, 0, len(astF.Imports)) for _, imp := range astF.Imports { sf.Imports = append(sf.Imports, imp.Path.Value) } sf.Consts = make([]string, 0, len(astF.Scope.Objects)) for _, obj := range astF.Scope.Objects { if obj.Kind != ast.Var { panic(`unknown non-variable in "_c2c_decoders.go"`) } value := obj.Decl.(*ast.ValueSpec) sf.Consts = append(sf.Consts, obj.Name) for _, value := range value.Values { if value, ok := value.(*ast.CompositeLit); ok { for _, kv := range value.Elts { if kv, ok := kv.(*ast.KeyValueExpr); ok { k := kv.Key.(*ast.BasicLit) v := kv.Value.(*ast.Ident) sf.Decoders = append(sf.Decoders, decoder{ Id: mustParseInt(k.Value), Func: v.Name, DecoderType: obj.Name, }) } else { panic(`unknown key value in ` + obj.Name + ` in "_c2c_decoders.go"`) } } } else { panic(`unknown non-map value in "_c2c_decoders.go"`) } } } sort.Slice(sf.Consts, func(i, j int) bool { return sf.Consts[i] < sf.Consts[j] }) sort.Sort(sf.Decoders) f, _ := os.OpenFile("c2c_switch.go", os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_TRUNC, 0o644) tmpl, err := template.New("template").Parse(codeTemplate) if err != nil { panic(err) } buffer := &bytes.Buffer{} err = tmpl.Execute(buffer, &sf) if err != nil { panic(err) } source, _ := format.Source(buffer.Bytes()) _, _ = f.Write(source) _ = f.Close() } func mustParseInt(s string) int64 { i, err := strconv.ParseInt(s, 10, 32) if err != nil { panic(err) } return i }