Skip to content

Commit 43878f4

Browse files
authored
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).
1 parent dc7e27a commit 43878f4

File tree

5 files changed

+121
-44
lines changed

5 files changed

+121
-44
lines changed

core/types/block.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ func (n *BlockNonce) UnmarshalText(input []byte) error {
6060
}
6161

6262
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
63-
//go:generate go run ../../rlp/rlpgen -type Header -internal_methods -out gen_header_rlp.go
63+
//go:generate go run ../../rlp/rlpgen -type Header -out gen_header_rlp.go
64+
//go:generate go run ../../libevm/cmd/internalise -file gen_header_rlp.go Header.EncodeRLP
6465

6566
// Header represents a block header in the Ethereum blockchain.
6667
type Header struct {

libevm/cmd/internalise/main.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright 2024 the libevm authors.
2+
//
3+
// The libevm additions to go-ethereum are free software: you can redistribute
4+
// them and/or modify them under the terms of the GNU Lesser General Public License
5+
// as published by the Free Software Foundation, either version 3 of the License,
6+
// or (at your option) any later version.
7+
//
8+
// The libevm additions are distributed in the hope that they will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
11+
// General Public License for more details.
12+
//
13+
// You should have received a copy of the GNU Lesser General Public License
14+
// along with the go-ethereum library. If not, see
15+
// <http://www.gnu.org/licenses/>.
16+
17+
// The internalise command modifies Go files in place, making exported methods
18+
// internal.
19+
//
20+
// Usage:
21+
//
22+
// internalise -file <filepath> <type>.<method> [<type>.<method> [...]]
23+
//
24+
// For example, with file foo.go containing declarations:
25+
//
26+
// func (f *Foo) Bar() { ... }
27+
//
28+
// func (Foo) Baz() { ... }
29+
//
30+
// running
31+
//
32+
// internalise -file foo.go Foo.Bar Foo.Baz
33+
//
34+
// results in
35+
//
36+
// func (f *Foo) bar() { ... }
37+
//
38+
// func (Foo) baz() { ... }
39+
package main
40+
41+
import (
42+
"flag"
43+
"fmt"
44+
"go/ast"
45+
"go/format"
46+
"go/parser"
47+
"go/token"
48+
"os"
49+
"strings"
50+
)
51+
52+
func main() {
53+
file := flag.String("file", "", "File to modify")
54+
flag.Parse()
55+
56+
if err := run(*file, flag.Args()...); err != nil {
57+
fmt.Fprint(os.Stderr, err)
58+
os.Exit(1)
59+
}
60+
}
61+
62+
func run(fileName string, args ...string) error {
63+
methods := make(map[string]map[string]struct{})
64+
for _, a := range args {
65+
a = strings.TrimPrefix(strings.TrimSpace(a), "*")
66+
parts := strings.Split(a, ".")
67+
if len(parts) != 2 {
68+
return fmt.Errorf("invalid method identifier %q", a)
69+
}
70+
typ, fn := parts[0], parts[1]
71+
if _, ok := methods[typ]; !ok {
72+
methods[typ] = make(map[string]struct{})
73+
}
74+
methods[typ][fn] = struct{}{}
75+
}
76+
77+
fset := token.NewFileSet()
78+
mode := parser.SkipObjectResolution | parser.ParseComments
79+
parsed, err := parser.ParseFile(fset, fileName, nil, mode)
80+
if err != nil {
81+
return fmt.Errorf("parser.ParseFile(%q): %v", fileName, err)
82+
}
83+
84+
for _, d := range parsed.Decls {
85+
fn, ok := d.(*ast.FuncDecl)
86+
if !ok || fn.Recv.NumFields() != 1 {
87+
continue
88+
}
89+
90+
var typ string
91+
switch t := fn.Recv.List[0].Type.(type) {
92+
case *ast.Ident:
93+
typ = t.Name
94+
case *ast.StarExpr:
95+
typ = t.X.(*ast.Ident).Name //nolint:forcetypeassert // Invariant of valid Go method
96+
}
97+
98+
name := &fn.Name.Name
99+
if _, ok := methods[typ][*name]; !ok {
100+
continue
101+
}
102+
if n := []rune(*name); n[0] >= 'A' && n[0] <= 'Z' {
103+
n[0] += 'a' - 'A'
104+
*name = string(n)
105+
}
106+
}
107+
108+
// Since we're not creating, the zero perm/mode is ignored.
109+
f, err := os.OpenFile(fileName, os.O_TRUNC|os.O_WRONLY, 0) //nolint:gosec // Variable file is under our direct control in go:generate
110+
if err != nil {
111+
return fmt.Errorf("os.OpenFile(%q, [write-only, truncate]): %v", fileName, err)
112+
}
113+
if err := format.Node(f, fset, parsed); err != nil {
114+
return fmt.Errorf("format.Node(%T): %v", parsed, err)
115+
}
116+
return f.Close()
117+
}

rlp/rlpgen/gen.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ type buildContext struct {
3535
rawValueType *types.Named
3636

3737
typeToStructCache map[types.Type]*rlpstruct.Type
38-
39-
internalMethods bool
4038
}
4139

4240
func newBuildContext(packageRLP *types.Package) *buildContext {
@@ -100,8 +98,6 @@ type genContext struct {
10098
inPackage *types.Package
10199
imports map[string]struct{}
102100
tempCounter int
103-
104-
internalMethods bool
105101
}
106102

107103
func newGenContext(inPackage *types.Package) *genContext {
@@ -740,7 +736,7 @@ func generateDecoder(ctx *genContext, typ string, op op) []byte {
740736

741737
result, code := op.genDecode(ctx)
742738
var b bytes.Buffer
743-
fmt.Fprintf(&b, "func (obj *%s) %s(dec *rlp.Stream) error {\n", typ, ctx.decoderMethod())
739+
fmt.Fprintf(&b, "func (obj *%s) DecodeRLP(dec *rlp.Stream) error {\n", typ)
744740
fmt.Fprint(&b, code)
745741
fmt.Fprintf(&b, " *obj = %s\n", result)
746742
fmt.Fprintf(&b, " return nil\n")
@@ -755,7 +751,7 @@ func generateEncoder(ctx *genContext, typ string, op op) []byte {
755751
ctx.addImport(pathOfPackageRLP)
756752

757753
var b bytes.Buffer
758-
fmt.Fprintf(&b, "func (obj *%s) %s(_w io.Writer) error {\n", typ, ctx.encoderMethod())
754+
fmt.Fprintf(&b, "func (obj *%s) EncodeRLP(_w io.Writer) error {\n", typ)
759755
fmt.Fprintf(&b, " w := rlp.NewEncoderBuffer(_w)\n")
760756
fmt.Fprint(&b, op.genWrite(ctx, "obj"))
761757
fmt.Fprintf(&b, " return w.Flush()\n")
@@ -777,7 +773,6 @@ func (bctx *buildContext) generate(typ *types.Named, encoder, decoder bool) ([]b
777773
encSource []byte
778774
decSource []byte
779775
)
780-
ctx.internalMethods = bctx.internalMethods
781776
if encoder {
782777
encSource = generateEncoder(ctx, typ.Obj().Name(), op)
783778
}

rlp/rlpgen/gen.libevm.go

Lines changed: 0 additions & 31 deletions
This file was deleted.

rlp/rlpgen/main.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ func main() {
3636
genEncoder = flag.Bool("encoder", true, "generate EncodeRLP?")
3737
genDecoder = flag.Bool("decoder", false, "generate DecodeRLP?")
3838
typename = flag.String("type", "", "type to generate methods for")
39-
internal = flag.Bool("internal_methods", false, "generate internal (lower-case) method names")
4039
)
4140
flag.Parse()
4241

@@ -45,7 +44,6 @@ func main() {
4544
Type: *typename,
4645
GenerateEncoder: *genEncoder,
4746
GenerateDecoder: *genDecoder,
48-
InternalMethods: *internal,
4947
}
5048
code, err := cfg.process()
5149
if err != nil {
@@ -69,8 +67,6 @@ type Config struct {
6967

7068
GenerateEncoder bool
7169
GenerateDecoder bool
72-
73-
InternalMethods bool
7470
}
7571

7672
// process generates the Go code.
@@ -105,7 +101,6 @@ func (cfg *Config) process() (code []byte, err error) {
105101
}
106102
}
107103
bctx := newBuildContext(packageRLP)
108-
bctx.internalMethods = cfg.InternalMethods
109104

110105
// Find the type and generate.
111106
typ, err := lookupStructType(pkg.Scope(), cfg.Type)

0 commit comments

Comments
 (0)