accounts/abi: implement struct parsing first attempt

Signed-off-by: VoR0220 <catalanor0220@gmail.com>
This commit is contained in:
VoR0220 2017-11-10 17:39:39 -06:00
parent 86f6568f66
commit a16610fc1e
2 changed files with 136 additions and 80 deletions

View file

@ -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

View file

@ -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