hdl.ast: allow typed int enums in Value.cast.

This commit is contained in:
Arusekk 2023-01-22 22:37:49 +01:00 committed by Catherine
parent 91d4513682
commit 58a0c68279
3 changed files with 31 additions and 4 deletions

View file

@ -168,12 +168,12 @@ class Value(metaclass=ABCMeta):
while True:
if isinstance(obj, Value):
return obj
elif isinstance(obj, int):
return Const(obj)
elif isinstance(obj, Enum):
return Const(obj.value, Shape.cast(type(obj)))
elif isinstance(obj, ValueCastable):
new_obj = obj.as_value()
elif isinstance(obj, Enum):
return Const(obj.value, Shape.cast(type(obj)))
elif isinstance(obj, int):
return Const(obj)
else:
raise TypeError("Object {!r} cannot be converted to an Amaranth value".format(obj))
if new_obj is obj:

View file

@ -235,6 +235,9 @@ Casting a value from an integer ``i`` is a shorthand for ``Const(i)``:
>>> Value.cast(5)
(const 3'd5)
.. note::
If a value subclasses :class:`enum.IntEnum` or its class otherwise inherits from both :class:`int` and :class:`Enum`, it is treated as an enumeration.
Values from enumeration members
-------------------------------
@ -247,6 +250,10 @@ Casting a value from an enumeration member ``m`` is a shorthand for ``Const(m.va
(const 2'd1)
.. note::
If a value subclasses :class:`enum.IntEnum` or its class otherwise inherits from both :class:`int` and :class:`Enum`, it is treated as an enumeration.
.. _lang-signals:
Signals

View file

@ -23,6 +23,12 @@ class StringEnum(Enum):
BAR = "b"
class TypedEnum(int, Enum):
FOO = 1
BAR = 2
BAZ = 3
class ShapeTestCase(FHDLTestCase):
def test_make(self):
s1 = Shape()
@ -199,6 +205,11 @@ class ValueTestCase(FHDLTestCase):
self.assertIsInstance(e2, Const)
self.assertEqual(e2.shape(), signed(2))
def test_cast_typedenum(self):
e1 = Value.cast(TypedEnum.FOO)
self.assertIsInstance(e1, Const)
self.assertEqual(e1.shape(), unsigned(2))
def test_cast_enum_wrong(self):
with self.assertRaisesRegex(TypeError,
r"^Only enumerations with integer values can be used as value shapes$"):
@ -781,6 +792,15 @@ class CatTestCase(FHDLTestCase):
warnings.filterwarnings(action="error", category=SyntaxWarning)
Cat(0, 1, 1, 0)
def test_enum(self):
class Color(Enum):
RED = 1
BLUE = 2
with warnings.catch_warnings():
warnings.filterwarnings(action="error", category=SyntaxWarning)
c = Cat(Color.RED, Color.BLUE)
self.assertEqual(repr(c), "(cat (const 2'd1) (const 2'd2))")
def test_int_wrong(self):
with self.assertWarnsRegex(SyntaxWarning,
r"^Argument #1 of Cat\(\) is a bare integer 2 used in bit vector context; "