github.com/klaytn/klaytn@v1.10.2/rlp/rlpgen/main.go (about) 1 // Modifications Copyright 2022 The klaytn Authors 2 // Copyright 2021 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from rlp/rlpgen/main.go(2022/05/19) 19 // Modified and improved for the klaytn development. 20 21 package main 22 23 import ( 24 "bytes" 25 "errors" 26 "flag" 27 "fmt" 28 "go/types" 29 "io/ioutil" 30 "os" 31 32 "golang.org/x/tools/go/packages" 33 ) 34 35 const pathOfPackageRLP = "github.com/klaytn/klaytn/rlp" 36 37 func main() { 38 var ( 39 pkgdir = flag.String("dir", ".", "input package") 40 output = flag.String("out", "-", "output file (default is stdout)") 41 genEncoder = flag.Bool("encoder", true, "generate EncodeRLP?") 42 genDecoder = flag.Bool("decoder", false, "generate DecodeRLP?") 43 typename = flag.String("type", "", "type to generate methods for") 44 ) 45 flag.Parse() 46 47 cfg := Config{ 48 Dir: *pkgdir, 49 Type: *typename, 50 GenerateEncoder: *genEncoder, 51 GenerateDecoder: *genDecoder, 52 } 53 code, err := cfg.process() 54 if err != nil { 55 fatal(err) 56 } 57 if *output == "-" { 58 os.Stdout.Write(code) 59 } else if err := ioutil.WriteFile(*output, code, 0o644); err != nil { 60 fatal(err) 61 } 62 } 63 64 func fatal(args ...interface{}) { 65 fmt.Fprintln(os.Stderr, args...) 66 os.Exit(1) 67 } 68 69 type Config struct { 70 Dir string // input package directory 71 Type string 72 73 GenerateEncoder bool 74 GenerateDecoder bool 75 } 76 77 // process generates the Go code. 78 func (cfg *Config) process() (code []byte, err error) { 79 // Load packages. 80 pcfg := &packages.Config{ 81 Mode: packages.NeedName | packages.NeedTypes | packages.NeedImports | packages.NeedDeps, 82 Dir: cfg.Dir, 83 BuildFlags: []string{"-tags", "norlpgen"}, 84 } 85 ps, err := packages.Load(pcfg, pathOfPackageRLP, ".") 86 if err != nil { 87 return nil, err 88 } 89 if len(ps) == 0 { 90 return nil, fmt.Errorf("no Go package found in %s", cfg.Dir) 91 } 92 packages.PrintErrors(ps) 93 94 // Find the packages that were loaded. 95 var ( 96 pkg *types.Package 97 packageRLP *types.Package 98 ) 99 for _, p := range ps { 100 if len(p.Errors) > 0 { 101 return nil, fmt.Errorf("package %s has errors", p.PkgPath) 102 } 103 if p.PkgPath == pathOfPackageRLP { 104 packageRLP = p.Types 105 } else { 106 pkg = p.Types 107 } 108 } 109 bctx := newBuildContext(packageRLP) 110 111 // Find the type and generate. 112 typ, err := lookupStructType(pkg.Scope(), cfg.Type) 113 if err != nil { 114 return nil, fmt.Errorf("can't find %s in %s: %v", typ, pkg, err) 115 } 116 code, err = bctx.generate(typ, cfg.GenerateEncoder, cfg.GenerateDecoder) 117 if err != nil { 118 return nil, err 119 } 120 121 // Add build comments. 122 // This is done here to avoid processing these lines with gofmt. 123 var header bytes.Buffer 124 fmt.Fprint(&header, "// Code generated by rlpgen. DO NOT EDIT.\n\n") 125 fmt.Fprint(&header, "//go:build !norlpgen\n") 126 fmt.Fprint(&header, "// +build !norlpgen\n\n") 127 return append(header.Bytes(), code...), nil 128 } 129 130 func lookupStructType(scope *types.Scope, name string) (*types.Named, error) { 131 typ, err := lookupType(scope, name) 132 if err != nil { 133 return nil, err 134 } 135 _, ok := typ.Underlying().(*types.Struct) 136 if !ok { 137 return nil, errors.New("not a struct type") 138 } 139 return typ, nil 140 } 141 142 func lookupType(scope *types.Scope, name string) (*types.Named, error) { 143 obj := scope.Lookup(name) 144 if obj == nil { 145 return nil, errors.New("no such identifier") 146 } 147 typ, ok := obj.(*types.TypeName) 148 if !ok { 149 return nil, errors.New("not a type") 150 } 151 return typ.Type().(*types.Named), nil 152 }