Skip to content

Commit

Permalink
Add array support for tuples
Browse files Browse the repository at this point in the history
  • Loading branch information
tristan committed Aug 7, 2018
1 parent 1a8d334 commit 6d3eff7
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 10 deletions.
15 changes: 13 additions & 2 deletions eth_abi/decoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,19 @@ def decode(self, stream):
@parse_tuple_type_str
def from_type_str(cls, abi_type, registry):
decoders = tuple(registry.get_decoder(str(c)) for c in abi_type.components)

return cls(decoders=decoders)
decoder = cls(decoders=decoders)
if abi_type.arrlist:
array_spec = abi_type.arrlist[-1]
if len(array_spec) == 1:
# If array dimension is fixed
return SizedArrayDecoder(
array_size=array_spec[0],
item_decoder=decoder,
)
else:
# If array dimension is dynamic
return DynamicArrayDecoder(item_decoder=decoder)
return decoder


class SingleDecoder(BaseDecoder):
Expand Down
15 changes: 13 additions & 2 deletions eth_abi/encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,19 @@ def encode(self, values):
@parse_tuple_type_str
def from_type_str(cls, abi_type, registry):
encoders = tuple(registry.get_encoder(str(c)) for c in abi_type.components)

return cls(encoders=encoders)
encoder = cls(encoders=encoders)
if abi_type.arrlist:
array_spec = abi_type.arrlist[-1]
if len(array_spec) == 1:
# If array dimension is fixed
return SizedArrayEncoder(
array_size=array_spec[0],
item_encoder=encoder,
)
else:
# If array dimension is dynamic
return DynamicArrayEncoder(item_encoder=encoder)
return encoder


class FixedSizeEncoder(BaseEncoder):
Expand Down
23 changes: 17 additions & 6 deletions eth_abi/grammar.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
grammar = parsimonious.Grammar(r"""
type = tuple_type / basic_type
tuple_type = non_zero_tuple / zero_tuple
tuple_type = base_tuple_type arrlist?
base_tuple_type = non_zero_tuple / zero_tuple
non_zero_tuple = "(" type next_type* ")"
next_type = "," type
Expand Down Expand Up @@ -48,7 +49,11 @@ def visit_non_zero_tuple(self, node, visited_children):
# Ignore left and right parens
_, first, rest, _ = visited_children

return TupleType((first,) + rest, node=node)
return (first,) + rest

def visit_tuple_type(self, node, visited_children):
base_tuple_type, arrlist = visited_children
return TupleType(base_tuple_type, arrlist=arrlist, node=node)

def visit_next_type(self, node, visited_children):
# Ignore comma
Expand All @@ -57,7 +62,7 @@ def visit_next_type(self, node, visited_children):
return abi_type

def visit_zero_tuple(self, node, visited_children):
return TupleType(tuple(), node=node)
return tuple()

def visit_basic_type(self, node, visited_children):
base, sub, arrlist = visited_children
Expand Down Expand Up @@ -184,15 +189,21 @@ class TupleType(ABIType):
e.g. "(int,bool)"
"""
__slots__ = ('components',)
__slots__ = ('components', 'arrlist')

def __init__(self, components, *, node=None):
def __init__(self, components, arrlist=None, *, node=None):
super().__init__(node=node)

self.components = components
self.arrlist = arrlist

def __str__(self):
return '({})'.format(','.join(str(c) for c in self.components))
arrlist = self.arrlist
if isinstance(arrlist, tuple):
arrlist = ''.join(repr(list(a)) for a in arrlist)
else:
arrlist = ''
return '({}){}'.format(','.join(str(c) for c in self.components), arrlist)

def validate(self):
# A tuple type is valid if all of its components are valid i.e. if none
Expand Down
10 changes: 10 additions & 0 deletions tests/common/unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@ def words(*descriptions: str) -> bytes:
(((1, 1), 2), 3),
words('40', '3', '40', '2', '2', '1', '1')
),
(
'((int,int)[])',
(((1, 2), (3, 4)),),
words('20', '2', '1', '2', '3', '4')
),
(
'((int,int[],(int,int)[]),(int,int),int)',
((1, (2, 3), ((4, 5), (6, 7))), (8, 9), 10),
words('80', '8', '9', 'a', '1', '60', 'c0', '2', '2', '3', '2', '4', '5', '6', '7')
),
(
'((bytes,bool),(bytes,bool))',
((b'david attenborough', False), (b'boaty mcboatface', True)),
Expand Down

0 comments on commit 6d3eff7

Please sign in to comment.