//go:build ignore package main import ( "bytes" "fmt" "go/ast" "go/format" "go/parser" "go/token" "os" ) var output bytes.Buffer func fprintf(format string, args ...interface{}) { _, _ = fmt.Fprintf(&output, format, args...) } func main() { f, _ := parser.ParseFile(token.NewFileSet(), "./../database.go", nil, 0) fprintf("// Code generated by mkrw.go; DO NOT EDIT.\n\n") fprintf("package leveldb\n\n") fprintf("import \"github.com/Mrs4s/go-cqhttp/db\"\n\n") ast.Inspect(f, func(node ast.Node) bool { switch node := node.(type) { case *ast.FuncDecl: return false case *ast.TypeSpec: if !node.Name.IsExported() { return false } x, ok := node.Type.(*ast.StructType) if !ok { return false } if x.Fields != nil && x.Fields.List != nil { mkWrite(node) mkRead(node) } } return true }) out, err := format.Source(output.Bytes()) if err != nil { fmt.Println(string(output.Bytes())) panic(err) } os.WriteFile("database_gen.go", out, 0o644) } func typeName(typ ast.Expr) string { switch typ := typ.(type) { case *ast.Ident: return typ.Name case *ast.ArrayType: if typ.Len != nil { panic("unexpected array type") } return "[]" + typeName(typ.Elt) case *ast.SelectorExpr: return typeName(typ.X) + "." + typ.Sel.Name } panic("unexpected type") } func mkWrite(node *ast.TypeSpec) { typename := node.Name.String() structType := node.Type.(*ast.StructType) fprintf("func (w *writer) write%s(x *db.%s) {\n", typename, typename) fprintf("if x == nil {\n") fprintf("w.nil()\n") fprintf("return\n") fprintf("}\n") fprintf("w.coder(coderStruct)\n") for _, field := range structType.Fields.List { switch typ := field.Type.(type) { case *ast.Ident: for _, name := range field.Names { fprintf("w.%s(x.%s)\n", typ.Name, name.Name) } case *ast.ArrayType: if typeName(typ) != "[]global.MSG" { panic("unexpected array type") } for _, name := range field.Names { fprintf("w.arrayMsg(x.%s)\n", name.Name) } case *ast.StarExpr: for _, name := range field.Names { fprintf("w.write%s(x.%s)\n", typeName(typ.X), name.Name) } } } fprintf("}\n\n") } func mkRead(node *ast.TypeSpec) { typename := node.Name.String() structType := node.Type.(*ast.StructType) fprintf(`func (r *reader) read%s() *db.%s { coder := r.coder() if coder == coderNil { return nil }`+"\n", typename, typename) fprintf("x := &db.%s{}\n", typename) for _, field := range structType.Fields.List { switch typ := field.Type.(type) { case *ast.Ident: for _, name := range field.Names { fprintf("x.%s = r.%s()\n", name.Name, typ.Name) } case *ast.ArrayType: if typeName(typ) != "[]global.MSG" { panic("unexpected array type") } for _, name := range field.Names { fprintf("x.%s = r.arrayMsg()\n", name.Name) } case *ast.StarExpr: for _, name := range field.Names { fprintf("x.%s = r.read%s()\n", name.Name, typeName(typ.X)) } } } fprintf("return x\n") fprintf("}\n\n") }