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
|
||||
}
|
||||
|
||||
func (a *Argument) UnmarshalJSON(data []byte) error {
|
||||
var extarg struct {
|
||||
// Type only used for unmarshalling json argument types
|
||||
type unmarshalArg struct {
|
||||
Name string
|
||||
Type string
|
||||
Components []unmarshalArg // used for tuples/structs
|
||||
Indexed bool
|
||||
}
|
||||
|
||||
func (a *Argument) UnmarshalJSON(data []byte) error {
|
||||
var extarg unmarshalArg
|
||||
|
||||
err := json.Unmarshal(data, &extarg)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.Name = extarg.Name
|
||||
a.Indexed = extarg.Indexed
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// Type enumerator
|
||||
const (
|
||||
IntTy byte = iota
|
||||
UintTy
|
||||
|
|
@ -37,6 +38,7 @@ const (
|
|||
HashTy
|
||||
FixedPointTy
|
||||
FunctionTy
|
||||
StructTy
|
||||
)
|
||||
|
||||
// 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.
|
||||
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
|
||||
// recursively create the type
|
||||
if strings.Count(t, "[") != 0 {
|
||||
i := strings.LastIndex(t, "[")
|
||||
// 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")
|
||||
}
|
||||
var found bool
|
||||
if typ, found, err = checkForSlices(t); found == true || err != nil {
|
||||
return typ, err
|
||||
} else {
|
||||
}
|
||||
|
||||
typ.stringKind = t
|
||||
// parse the type and size of the abi-type.
|
||||
parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0]
|
||||
// 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 := parsedType[1]
|
||||
|
||||
switch varType {
|
||||
switch varType := parsedType[1]; varType {
|
||||
case "int":
|
||||
typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
|
||||
typ.Size = varSize
|
||||
|
|
@ -162,11 +128,90 @@ func NewType(t string) (typ Type, err error) {
|
|||
default:
|
||||
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
func (t Type) String() (out string) {
|
||||
return t.stringKind
|
||||
|
|
|
|||
Loading…
Reference in a new issue