hdl.ast: don't inherit Shape from NamedTuple.

Fixes #421.
This commit is contained in:
awygle 2020-07-06 22:17:03 -07:00 committed by GitHub
parent cee43f0de1
commit 659b0e8189
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 10 deletions

View file

@ -32,7 +32,7 @@ class DUID:
DUID.__next_uid += 1
class Shape(typing.NamedTuple):
class Shape:
"""Bit width and signedness of a value.
A ``Shape`` can be constructed using:
@ -55,8 +55,15 @@ class Shape(typing.NamedTuple):
signed : bool
If ``False``, the value is unsigned. If ``True``, the value is signed two's complement.
"""
width: int = 1
signed: bool = False
def __init__(self, width=1, signed=False):
if not isinstance(width, int) or width < 0:
raise TypeError("Width must be a non-negative integer, not {!r}"
.format(width))
self.width = width
self.signed = signed
def __iter__(self):
return iter((self.width, self.signed))
@staticmethod
def cast(obj, *, src_loc_at=0):
@ -95,13 +102,20 @@ class Shape(typing.NamedTuple):
else:
return "unsigned({})".format(self.width)
# TODO: use dataclasses instead of this hack
def _Shape___init__(self, width=1, signed=False):
if not isinstance(width, int) or width < 0:
raise TypeError("Width must be a non-negative integer, not {!r}"
.format(width))
Shape.__init__ = _Shape___init__
def __eq__(self, other):
if isinstance(other, tuple) and len(other) == 2:
width, signed = other
if isinstance(width, int) and isinstance(signed, bool):
return self.width == width and self.signed == signed
else:
raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
"not {!r}"
.format(other))
if not isinstance(other, Shape):
raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
"not {!r}"
.format(other))
return self.width == other.width and self.signed == other.signed
def unsigned(width):

View file

@ -39,6 +39,16 @@ class ShapeTestCase(FHDLTestCase):
msg="Width must be a non-negative integer, not -1"):
Shape(-1)
def test_compare_wrong(self):
with self.assertRaises(TypeError,
msg="Shapes may be compared with other Shapes and (int, bool) tuples, not 'hi'"):
Shape(1, True) == 'hi'
def test_compare_tuple_wrong(self):
with self.assertRaises(TypeError,
msg="Shapes may be compared with other Shapes and (int, bool) tuples, not (2, 3)"):
Shape(1, True) == (2, 3)
def test_repr(self):
self.assertEqual(repr(Shape()), "unsigned(1)")
self.assertEqual(repr(Shape(2, True)), "signed(2)")