binding: make TemplateFromManifest more reusable

Other template generators can make use of it.
This commit is contained in:
Roman Khimov 2022-10-26 12:43:48 +03:00
parent d6d4f07280
commit 4191b18728

View file

@ -55,24 +55,24 @@ type (
Output io.Writer `yaml:"-"` Output io.Writer `yaml:"-"`
} }
contractTmpl struct { ContractTmpl struct {
PackageName string PackageName string
ContractName string ContractName string
Imports []string Imports []string
Hash string Hash string
Methods []methodTmpl Methods []MethodTmpl
} }
methodTmpl struct { MethodTmpl struct {
Name string Name string
NameABI string NameABI string
CallFlag string CallFlag string
Comment string Comment string
Arguments []paramTmpl Arguments []ParamTmpl
ReturnType string ReturnType string
} }
paramTmpl struct { ParamTmpl struct {
Name string Name string
Type string Type string
} }
@ -88,7 +88,7 @@ func NewConfig() Config {
// Generate writes Go file containing smartcontract bindings to the `cfg.Output`. // Generate writes Go file containing smartcontract bindings to the `cfg.Output`.
func Generate(cfg Config) error { func Generate(cfg Config) error {
ctr, err := templateFromManifest(cfg) ctr, err := TemplateFromManifest(cfg, scTypeToGo)
if err != nil { if err != nil {
return err return err
} }
@ -98,7 +98,6 @@ func Generate(cfg Config) error {
tmp, err := template.New("generate").Funcs(template.FuncMap{ tmp, err := template.New("generate").Funcs(template.FuncMap{
"lowerFirst": lowerFirst, "lowerFirst": lowerFirst,
"scTypeToGo": scTypeToGo,
}).Parse(srcTmpl) }).Parse(srcTmpl)
if err != nil { if err != nil {
return err return err
@ -107,46 +106,52 @@ func Generate(cfg Config) error {
return tmp.Execute(cfg.Output, ctr) return tmp.Execute(cfg.Output, ctr)
} }
func scTypeToGo(typ smartcontract.ParamType) string { func scTypeToGo(name string, typ smartcontract.ParamType, overrides map[string]Override) (string, string) {
if over, ok := overrides[name]; ok {
return over.TypeName, over.Package
}
switch typ { switch typ {
case smartcontract.AnyType: case smartcontract.AnyType:
return "interface{}" return "interface{}", ""
case smartcontract.BoolType: case smartcontract.BoolType:
return "bool" return "bool", ""
case smartcontract.IntegerType: case smartcontract.IntegerType:
return "int" return "int", ""
case smartcontract.ByteArrayType: case smartcontract.ByteArrayType:
return "[]byte" return "[]byte", ""
case smartcontract.StringType: case smartcontract.StringType:
return "string" return "string", ""
case smartcontract.Hash160Type: case smartcontract.Hash160Type:
return "interop.Hash160" return "interop.Hash160", "github.com/nspcc-dev/neo-go/pkg/interop"
case smartcontract.Hash256Type: case smartcontract.Hash256Type:
return "interop.Hash256" return "interop.Hash256", "github.com/nspcc-dev/neo-go/pkg/interop"
case smartcontract.PublicKeyType: case smartcontract.PublicKeyType:
return "interop.PublicKey" return "interop.PublicKey", "github.com/nspcc-dev/neo-go/pkg/interop"
case smartcontract.SignatureType: case smartcontract.SignatureType:
return "interop.Signature" return "interop.Signature", "github.com/nspcc-dev/neo-go/pkg/interop"
case smartcontract.ArrayType: case smartcontract.ArrayType:
return "[]interface{}" return "[]interface{}", ""
case smartcontract.MapType: case smartcontract.MapType:
return "map[string]interface{}" return "map[string]interface{}", ""
case smartcontract.InteropInterfaceType: case smartcontract.InteropInterfaceType:
return "interface{}" return "interface{}", ""
case smartcontract.VoidType: case smartcontract.VoidType:
return "" return "", ""
default: default:
panic("unreachable") panic("unreachable")
} }
} }
func templateFromManifest(cfg Config) (contractTmpl, error) { // TemplateFromManifest create a contract template using the given configuration
// and type conversion function.
func TemplateFromManifest(cfg Config, scTypeConverter func(string, smartcontract.ParamType, map[string]Override) (string, string)) (ContractTmpl, error) {
hStr := "" hStr := ""
for _, b := range cfg.Hash.BytesBE() { for _, b := range cfg.Hash.BytesBE() {
hStr += fmt.Sprintf("\\x%02x", b) hStr += fmt.Sprintf("\\x%02x", b)
} }
ctr := contractTmpl{ ctr := ContractTmpl{
PackageName: cfg.Package, PackageName: cfg.Package,
ContractName: cfg.Manifest.Name, ContractName: cfg.Manifest.Name,
Hash: hStr, Hash: hStr,
@ -187,7 +192,7 @@ func templateFromManifest(cfg Config) (contractTmpl, error) {
} }
seen[name] = true seen[name] = true
mtd := methodTmpl{ mtd := MethodTmpl{
Name: upperFirst(name), Name: upperFirst(name),
NameABI: m.Name, NameABI: m.Name,
CallFlag: callflag.All.String(), CallFlag: callflag.All.String(),
@ -204,36 +209,22 @@ func templateFromManifest(cfg Config) (contractTmpl, error) {
return ctr, fmt.Errorf("manifest ABI method %q/%d: parameter #%d is unnamed", m.Name, len(m.Parameters), i) return ctr, fmt.Errorf("manifest ABI method %q/%d: parameter #%d is unnamed", m.Name, len(m.Parameters), i)
} }
var typeStr string typeStr, pkg := scTypeConverter(m.Name+"."+name, m.Parameters[i].Type, cfg.Overrides)
if over, ok := cfg.Overrides[m.Name+"."+name]; ok { if pkg != "" {
typeStr = over.TypeName imports[pkg] = struct{}{}
if over.Package != "" {
imports[over.Package] = struct{}{}
}
} else {
typeStr = scTypeToGo(m.Parameters[i].Type)
} }
mtd.Arguments = append(mtd.Arguments, paramTmpl{ mtd.Arguments = append(mtd.Arguments, ParamTmpl{
Name: name, Name: name,
Type: typeStr, Type: typeStr,
}) })
} }
if over, ok := cfg.Overrides[m.Name]; ok { typeStr, pkg := scTypeConverter(m.Name, m.ReturnType, cfg.Overrides)
mtd.ReturnType = over.TypeName if pkg != "" {
if over.Package != "" { imports[pkg] = struct{}{}
imports[over.Package] = struct{}{}
} }
} else { mtd.ReturnType = typeStr
mtd.ReturnType = scTypeToGo(m.ReturnType)
switch m.ReturnType {
case smartcontract.Hash160Type, smartcontract.Hash256Type, smartcontract.InteropInterfaceType,
smartcontract.SignatureType, smartcontract.PublicKeyType:
imports["github.com/nspcc-dev/neo-go/pkg/interop"] = struct{}{}
}
}
ctr.Methods = append(ctr.Methods, mtd) ctr.Methods = append(ctr.Methods, mtd)
} }