mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 17:33:47 +00:00
accounts/abi: implement struct parsing first attempt
Signed-off-by: VoR0220 <catalanor0220@gmail.com>
This commit is contained in:
parent
86f6568f66
commit
a16610fc1e
2 changed files with 136 additions and 80 deletions
|
|
@ -29,21 +29,32 @@ type Argument struct {
|
||||||
Indexed bool // indexed is only used by events
|
Indexed bool // indexed is only used by events
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Argument) UnmarshalJSON(data []byte) error {
|
// Type only used for unmarshalling json argument types
|
||||||
var extarg struct {
|
type unmarshalArg struct {
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
|
Components []unmarshalArg // used for tuples/structs
|
||||||
Indexed bool
|
Indexed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Argument) UnmarshalJSON(data []byte) error {
|
||||||
|
var extarg unmarshalArg
|
||||||
|
|
||||||
err := json.Unmarshal(data, &extarg)
|
err := json.Unmarshal(data, &extarg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("argument json err: %v", err)
|
return fmt.Errorf("argument json err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(extarg.Components) > 0 {
|
||||||
|
a.Type, err = ParseStructType(extarg.Type, extarg.Components...)
|
||||||
|
} else {
|
||||||
a.Type, err = NewType(extarg.Type)
|
a.Type, err = NewType(extarg.Type)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.Name = extarg.Name
|
a.Name = extarg.Name
|
||||||
a.Indexed = extarg.Indexed
|
a.Indexed = extarg.Indexed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Type enumerator
|
||||||
const (
|
const (
|
||||||
IntTy byte = iota
|
IntTy byte = iota
|
||||||
UintTy
|
UintTy
|
||||||
|
|
@ -37,6 +38,7 @@ const (
|
||||||
HashTy
|
HashTy
|
||||||
FixedPointTy
|
FixedPointTy
|
||||||
FunctionTy
|
FunctionTy
|
||||||
|
StructTy
|
||||||
)
|
)
|
||||||
|
|
||||||
// Type is the reflection of the supported argument type
|
// Type is the reflection of the supported argument type
|
||||||
|
|
@ -58,49 +60,15 @@ var (
|
||||||
|
|
||||||
// NewType creates a new reflection type of abi type given in t.
|
// NewType creates a new reflection type of abi type given in t.
|
||||||
func NewType(t string) (typ Type, err error) {
|
func NewType(t string) (typ Type, err error) {
|
||||||
// check that array brackets are equal if they exist
|
|
||||||
if strings.Count(t, "[") != strings.Count(t, "]") {
|
|
||||||
return Type{}, fmt.Errorf("invalid arg type in abi")
|
|
||||||
}
|
|
||||||
|
|
||||||
typ.stringKind = t
|
|
||||||
|
|
||||||
// if there are brackets, get ready to go into slice/array mode and
|
// if there are brackets, get ready to go into slice/array mode and
|
||||||
// recursively create the type
|
// recursively create the type
|
||||||
if strings.Count(t, "[") != 0 {
|
var found bool
|
||||||
i := strings.LastIndex(t, "[")
|
if typ, found, err = checkForSlices(t); found == true || err != nil {
|
||||||
// recursively embed the type
|
|
||||||
embeddedType, err := NewType(t[:i])
|
|
||||||
if err != nil {
|
|
||||||
return Type{}, err
|
|
||||||
}
|
|
||||||
// grab the last cell and create a type from there
|
|
||||||
sliced := t[i:]
|
|
||||||
// grab the slice size with regexp
|
|
||||||
re := regexp.MustCompile("[0-9]+")
|
|
||||||
intz := re.FindAllString(sliced, -1)
|
|
||||||
|
|
||||||
if len(intz) == 0 {
|
|
||||||
// is a slice
|
|
||||||
typ.T = SliceTy
|
|
||||||
typ.Kind = reflect.Slice
|
|
||||||
typ.Elem = &embeddedType
|
|
||||||
typ.Type = reflect.SliceOf(embeddedType.Type)
|
|
||||||
} else if len(intz) == 1 {
|
|
||||||
// is a array
|
|
||||||
typ.T = ArrayTy
|
|
||||||
typ.Kind = reflect.Array
|
|
||||||
typ.Elem = &embeddedType
|
|
||||||
typ.Size, err = strconv.Atoi(intz[0])
|
|
||||||
if err != nil {
|
|
||||||
return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
|
|
||||||
}
|
|
||||||
typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
|
|
||||||
} else {
|
|
||||||
return Type{}, fmt.Errorf("invalid formatting of array type")
|
|
||||||
}
|
|
||||||
return typ, err
|
return typ, err
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
typ.stringKind = t
|
||||||
// parse the type and size of the abi-type.
|
// parse the type and size of the abi-type.
|
||||||
parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0]
|
parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0]
|
||||||
// varSize is the size of the variable
|
// varSize is the size of the variable
|
||||||
|
|
@ -119,9 +87,7 @@ func NewType(t string) (typ Type, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// varType is the parsed abi type
|
// varType is the parsed abi type
|
||||||
varType := parsedType[1]
|
switch varType := parsedType[1]; varType {
|
||||||
|
|
||||||
switch varType {
|
|
||||||
case "int":
|
case "int":
|
||||||
typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
|
typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
|
||||||
typ.Size = varSize
|
typ.Size = varSize
|
||||||
|
|
@ -162,11 +128,90 @@ func NewType(t string) (typ Type, err error) {
|
||||||
default:
|
default:
|
||||||
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if brackets surround the type, create it recursively, otherwise note that brackets weren't found
|
||||||
|
func checkForSlices(t string, structComponents ...unmarshalArg) (typ Type, found bool, err error) {
|
||||||
|
// check that array brackets are equal if they exist
|
||||||
|
if strings.Count(t, "[") != strings.Count(t, "]") {
|
||||||
|
return Type{}, false, fmt.Errorf("invalid arg type in abi")
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Count(t, "[") != 0 {
|
||||||
|
i := strings.LastIndex(t, "[")
|
||||||
|
// recursively embed the type
|
||||||
|
var embeddedType Type
|
||||||
|
if len(structComponents) > 0 {
|
||||||
|
embeddedType, err = ParseStructType(t, structComponents...)
|
||||||
|
} else {
|
||||||
|
embeddedType, err = NewType(t[:i])
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return Type{}, false, err
|
||||||
|
}
|
||||||
|
// grab the last cell and create a type from there
|
||||||
|
sliced := t[i:]
|
||||||
|
// grab the slice size with regexp
|
||||||
|
re := regexp.MustCompile("[0-9]+")
|
||||||
|
intz := re.FindAllString(sliced, -1)
|
||||||
|
|
||||||
|
if len(intz) == 0 {
|
||||||
|
// is a slice
|
||||||
|
typ.T = SliceTy
|
||||||
|
typ.Kind = reflect.Slice
|
||||||
|
typ.Elem = &embeddedType
|
||||||
|
typ.Type = reflect.SliceOf(embeddedType.Type)
|
||||||
|
} else if len(intz) == 1 {
|
||||||
|
// is a array
|
||||||
|
typ.T = ArrayTy
|
||||||
|
typ.Kind = reflect.Array
|
||||||
|
typ.Elem = &embeddedType
|
||||||
|
typ.Size, err = strconv.Atoi(intz[0])
|
||||||
|
if err != nil {
|
||||||
|
return Type{}, false, fmt.Errorf("abi: error parsing variable size: %v", err)
|
||||||
|
}
|
||||||
|
typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
|
||||||
|
} else {
|
||||||
|
return Type{}, false, fmt.Errorf("invalid formatting of array type")
|
||||||
|
}
|
||||||
|
return typ, true, err
|
||||||
|
}
|
||||||
|
return Type{}, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseStructType(t string, components ...unmarshalArg) (typ Type, err error) {
|
||||||
|
// if there are brackets, get ready to go into slice/array mode and
|
||||||
|
// recursively create the type
|
||||||
|
var found bool
|
||||||
|
if typ, found, err = checkForSlices(t, components...); found == true || err != nil {
|
||||||
|
return typ, err
|
||||||
|
}
|
||||||
|
typ.stringKind = t
|
||||||
|
typ.T = StructTy
|
||||||
|
typ.Kind = reflect.Struct
|
||||||
|
// create the struct type
|
||||||
|
var fields []reflect.StructField
|
||||||
|
for i, component := range components {
|
||||||
|
// it's a embedded struct type
|
||||||
|
var fieldType Type
|
||||||
|
|
||||||
|
if len(component.Components) > 0 {
|
||||||
|
fieldType, err = ParseStructType(component.Type, component.Components...)
|
||||||
|
} else {
|
||||||
|
fieldType, err = NewType(component.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return Type{}, err
|
||||||
|
}
|
||||||
|
fields[i] = reflect.StructField{Name: component.Name, Type: fieldType.Type, Tag: reflect.StructTag(fmt.Sprintf(`json:"%v"`, component.Name))}
|
||||||
|
}
|
||||||
|
typ.Type = reflect.StructOf(fields)
|
||||||
|
return typ, nil
|
||||||
|
}
|
||||||
|
|
||||||
// String implements Stringer
|
// String implements Stringer
|
||||||
func (t Type) String() (out string) {
|
func (t Type) String() (out string) {
|
||||||
return t.stringKind
|
return t.stringKind
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue