github.com/theQRL/go-zond@v0.1.1/rlp/rlpgen/main.go (about)

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