mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-27 00:46:18 +00:00
feat: internalise command (#90)
## Why this should be merged Replaces #86. That approach couldn't be replicated for generated JSON marshalling, and this once also reduces the upstream delta. ## How this works AST manipulation of a specified file, which finds specified methods and modifies their names to be unexported. ## How this was tested Inspection of the output (`core/types/gen_header_rlp.go` remains unchanged).
This commit is contained in:
parent
dc7e27aff4
commit
43878f4fab
5 changed files with 121 additions and 44 deletions
|
|
@ -60,7 +60,8 @@ func (n *BlockNonce) UnmarshalText(input []byte) error {
|
|||
}
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
|
||||
//go:generate go run ../../rlp/rlpgen -type Header -internal_methods -out gen_header_rlp.go
|
||||
//go:generate go run ../../rlp/rlpgen -type Header -out gen_header_rlp.go
|
||||
//go:generate go run ../../libevm/cmd/internalise -file gen_header_rlp.go Header.EncodeRLP
|
||||
|
||||
// Header represents a block header in the Ethereum blockchain.
|
||||
type Header struct {
|
||||
|
|
|
|||
117
libevm/cmd/internalise/main.go
Normal file
117
libevm/cmd/internalise/main.go
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright 2024 the libevm authors.
|
||||
//
|
||||
// The libevm additions to go-ethereum are free software: you can redistribute
|
||||
// them and/or modify them under the terms of the GNU Lesser General Public License
|
||||
// as published by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// The libevm additions are distributed in the hope that they will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// The internalise command modifies Go files in place, making exported methods
|
||||
// internal.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// internalise -file <filepath> <type>.<method> [<type>.<method> [...]]
|
||||
//
|
||||
// For example, with file foo.go containing declarations:
|
||||
//
|
||||
// func (f *Foo) Bar() { ... }
|
||||
//
|
||||
// func (Foo) Baz() { ... }
|
||||
//
|
||||
// running
|
||||
//
|
||||
// internalise -file foo.go Foo.Bar Foo.Baz
|
||||
//
|
||||
// results in
|
||||
//
|
||||
// func (f *Foo) bar() { ... }
|
||||
//
|
||||
// func (Foo) baz() { ... }
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
file := flag.String("file", "", "File to modify")
|
||||
flag.Parse()
|
||||
|
||||
if err := run(*file, flag.Args()...); err != nil {
|
||||
fmt.Fprint(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run(fileName string, args ...string) error {
|
||||
methods := make(map[string]map[string]struct{})
|
||||
for _, a := range args {
|
||||
a = strings.TrimPrefix(strings.TrimSpace(a), "*")
|
||||
parts := strings.Split(a, ".")
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("invalid method identifier %q", a)
|
||||
}
|
||||
typ, fn := parts[0], parts[1]
|
||||
if _, ok := methods[typ]; !ok {
|
||||
methods[typ] = make(map[string]struct{})
|
||||
}
|
||||
methods[typ][fn] = struct{}{}
|
||||
}
|
||||
|
||||
fset := token.NewFileSet()
|
||||
mode := parser.SkipObjectResolution | parser.ParseComments
|
||||
parsed, err := parser.ParseFile(fset, fileName, nil, mode)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parser.ParseFile(%q): %v", fileName, err)
|
||||
}
|
||||
|
||||
for _, d := range parsed.Decls {
|
||||
fn, ok := d.(*ast.FuncDecl)
|
||||
if !ok || fn.Recv.NumFields() != 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
var typ string
|
||||
switch t := fn.Recv.List[0].Type.(type) {
|
||||
case *ast.Ident:
|
||||
typ = t.Name
|
||||
case *ast.StarExpr:
|
||||
typ = t.X.(*ast.Ident).Name //nolint:forcetypeassert // Invariant of valid Go method
|
||||
}
|
||||
|
||||
name := &fn.Name.Name
|
||||
if _, ok := methods[typ][*name]; !ok {
|
||||
continue
|
||||
}
|
||||
if n := []rune(*name); n[0] >= 'A' && n[0] <= 'Z' {
|
||||
n[0] += 'a' - 'A'
|
||||
*name = string(n)
|
||||
}
|
||||
}
|
||||
|
||||
// Since we're not creating, the zero perm/mode is ignored.
|
||||
f, err := os.OpenFile(fileName, os.O_TRUNC|os.O_WRONLY, 0) //nolint:gosec // Variable file is under our direct control in go:generate
|
||||
if err != nil {
|
||||
return fmt.Errorf("os.OpenFile(%q, [write-only, truncate]): %v", fileName, err)
|
||||
}
|
||||
if err := format.Node(f, fset, parsed); err != nil {
|
||||
return fmt.Errorf("format.Node(%T): %v", parsed, err)
|
||||
}
|
||||
return f.Close()
|
||||
}
|
||||
|
|
@ -35,8 +35,6 @@ type buildContext struct {
|
|||
rawValueType *types.Named
|
||||
|
||||
typeToStructCache map[types.Type]*rlpstruct.Type
|
||||
|
||||
internalMethods bool
|
||||
}
|
||||
|
||||
func newBuildContext(packageRLP *types.Package) *buildContext {
|
||||
|
|
@ -100,8 +98,6 @@ type genContext struct {
|
|||
inPackage *types.Package
|
||||
imports map[string]struct{}
|
||||
tempCounter int
|
||||
|
||||
internalMethods bool
|
||||
}
|
||||
|
||||
func newGenContext(inPackage *types.Package) *genContext {
|
||||
|
|
@ -740,7 +736,7 @@ func generateDecoder(ctx *genContext, typ string, op op) []byte {
|
|||
|
||||
result, code := op.genDecode(ctx)
|
||||
var b bytes.Buffer
|
||||
fmt.Fprintf(&b, "func (obj *%s) %s(dec *rlp.Stream) error {\n", typ, ctx.decoderMethod())
|
||||
fmt.Fprintf(&b, "func (obj *%s) DecodeRLP(dec *rlp.Stream) error {\n", typ)
|
||||
fmt.Fprint(&b, code)
|
||||
fmt.Fprintf(&b, " *obj = %s\n", result)
|
||||
fmt.Fprintf(&b, " return nil\n")
|
||||
|
|
@ -755,7 +751,7 @@ func generateEncoder(ctx *genContext, typ string, op op) []byte {
|
|||
ctx.addImport(pathOfPackageRLP)
|
||||
|
||||
var b bytes.Buffer
|
||||
fmt.Fprintf(&b, "func (obj *%s) %s(_w io.Writer) error {\n", typ, ctx.encoderMethod())
|
||||
fmt.Fprintf(&b, "func (obj *%s) EncodeRLP(_w io.Writer) error {\n", typ)
|
||||
fmt.Fprintf(&b, " w := rlp.NewEncoderBuffer(_w)\n")
|
||||
fmt.Fprint(&b, op.genWrite(ctx, "obj"))
|
||||
fmt.Fprintf(&b, " return w.Flush()\n")
|
||||
|
|
@ -777,7 +773,6 @@ func (bctx *buildContext) generate(typ *types.Named, encoder, decoder bool) ([]b
|
|||
encSource []byte
|
||||
decSource []byte
|
||||
)
|
||||
ctx.internalMethods = bctx.internalMethods
|
||||
if encoder {
|
||||
encSource = generateEncoder(ctx, typ.Obj().Name(), op)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
// Copyright 2024 the libevm authors.
|
||||
//
|
||||
// The libevm additions to go-ethereum are free software: you can redistribute
|
||||
// them and/or modify them under the terms of the GNU Lesser General Public License
|
||||
// as published by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// The libevm additions are distributed in the hope that they will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main
|
||||
|
||||
func (ctx *genContext) encoderMethod() string {
|
||||
if ctx.internalMethods {
|
||||
return "encodeRLP"
|
||||
}
|
||||
return "EncodeRLP"
|
||||
}
|
||||
|
||||
func (ctx *genContext) decoderMethod() string {
|
||||
if ctx.internalMethods {
|
||||
return "decodeRLP"
|
||||
}
|
||||
return "DecodeRLP"
|
||||
}
|
||||
|
|
@ -36,7 +36,6 @@ func main() {
|
|||
genEncoder = flag.Bool("encoder", true, "generate EncodeRLP?")
|
||||
genDecoder = flag.Bool("decoder", false, "generate DecodeRLP?")
|
||||
typename = flag.String("type", "", "type to generate methods for")
|
||||
internal = flag.Bool("internal_methods", false, "generate internal (lower-case) method names")
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
|
|
@ -45,7 +44,6 @@ func main() {
|
|||
Type: *typename,
|
||||
GenerateEncoder: *genEncoder,
|
||||
GenerateDecoder: *genDecoder,
|
||||
InternalMethods: *internal,
|
||||
}
|
||||
code, err := cfg.process()
|
||||
if err != nil {
|
||||
|
|
@ -69,8 +67,6 @@ type Config struct {
|
|||
|
||||
GenerateEncoder bool
|
||||
GenerateDecoder bool
|
||||
|
||||
InternalMethods bool
|
||||
}
|
||||
|
||||
// process generates the Go code.
|
||||
|
|
@ -105,7 +101,6 @@ func (cfg *Config) process() (code []byte, err error) {
|
|||
}
|
||||
}
|
||||
bctx := newBuildContext(packageRLP)
|
||||
bctx.internalMethods = cfg.InternalMethods
|
||||
|
||||
// Find the type and generate.
|
||||
typ, err := lookupStructType(pkg.Scope(), cfg.Type)
|
||||
|
|
|
|||
Loading…
Reference in a new issue