hdl.ast: don't inherit Shape from NamedTuple.
[nmigen.git] / nmigen / test / test_hdl_ast.py
index c0d26eec9cf99764704177ee3c240c81de741a89..691408a0363e9a4d3bdea0f659b0888863420cec 100644 (file)
@@ -39,6 +39,20 @@ 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)")
+
     def test_tuple(self):
         width, signed = Shape()
         self.assertEqual(width, 1)
@@ -155,7 +169,7 @@ class ValueTestCase(FHDLTestCase):
 
     def test_bool(self):
         with self.assertRaises(TypeError,
-                msg="Attempted to convert nMigen value to boolean"):
+                msg="Attempted to convert nMigen value to Python boolean"):
             if Const(0):
                 pass
 
@@ -201,6 +215,94 @@ class ValueTestCase(FHDLTestCase):
                 msg="Cannot index value with 'str'"):
             Const(31)["str"]
 
+    def test_shift_left(self):
+        self.assertRepr(Const(256, unsigned(9)).shift_left(0),
+                        "(cat (const 0'd0) (const 9'd256))")
+
+        self.assertRepr(Const(256, unsigned(9)).shift_left(1),
+                        "(cat (const 1'd0) (const 9'd256))")
+        self.assertRepr(Const(256, unsigned(9)).shift_left(5),
+                        "(cat (const 5'd0) (const 9'd256))")
+        self.assertRepr(Const(256, signed(9)).shift_left(1),
+                        "(s (cat (const 1'd0) (const 9'sd-256)))")
+        self.assertRepr(Const(256, signed(9)).shift_left(5),
+                        "(s (cat (const 5'd0) (const 9'sd-256)))")
+
+        self.assertRepr(Const(256, unsigned(9)).shift_left(-1),
+                        "(slice (const 9'd256) 1:9)")
+        self.assertRepr(Const(256, unsigned(9)).shift_left(-5),
+                        "(slice (const 9'd256) 5:9)")
+        self.assertRepr(Const(256, signed(9)).shift_left(-1),
+                        "(s (slice (const 9'sd-256) 1:9))")
+        self.assertRepr(Const(256, signed(9)).shift_left(-5),
+                        "(s (slice (const 9'sd-256) 5:9))")
+        self.assertRepr(Const(256, signed(9)).shift_left(-15),
+                        "(s (slice (const 9'sd-256) 9:9))")
+
+    def test_shift_left_wrong(self):
+        with self.assertRaises(TypeError,
+                msg="Shift amount must be an integer, not 'str'"):
+            Const(31).shift_left("str")
+
+    def test_shift_right(self):
+        self.assertRepr(Const(256, unsigned(9)).shift_right(0),
+                        "(slice (const 9'd256) 0:9)")
+
+        self.assertRepr(Const(256, unsigned(9)).shift_right(-1),
+                        "(cat (const 1'd0) (const 9'd256))")
+        self.assertRepr(Const(256, unsigned(9)).shift_right(-5),
+                        "(cat (const 5'd0) (const 9'd256))")
+        self.assertRepr(Const(256, signed(9)).shift_right(-1),
+                        "(s (cat (const 1'd0) (const 9'sd-256)))")
+        self.assertRepr(Const(256, signed(9)).shift_right(-5),
+                        "(s (cat (const 5'd0) (const 9'sd-256)))")
+
+        self.assertRepr(Const(256, unsigned(9)).shift_right(1),
+                        "(slice (const 9'd256) 1:9)")
+        self.assertRepr(Const(256, unsigned(9)).shift_right(5),
+                        "(slice (const 9'd256) 5:9)")
+        self.assertRepr(Const(256, signed(9)).shift_right(1),
+                        "(s (slice (const 9'sd-256) 1:9))")
+        self.assertRepr(Const(256, signed(9)).shift_right(5),
+                        "(s (slice (const 9'sd-256) 5:9))")
+        self.assertRepr(Const(256, signed(9)).shift_right(15),
+                        "(s (slice (const 9'sd-256) 9:9))")
+
+    def test_shift_right_wrong(self):
+        with self.assertRaises(TypeError,
+                msg="Shift amount must be an integer, not 'str'"):
+            Const(31).shift_left("str")
+
+    def test_rotate_left(self):
+        self.assertRepr(Const(256).rotate_left(1),
+                        "(cat (slice (const 9'd256) 8:9) (slice (const 9'd256) 0:8))")
+        self.assertRepr(Const(256).rotate_left(7),
+                        "(cat (slice (const 9'd256) 2:9) (slice (const 9'd256) 0:2))")
+        self.assertRepr(Const(256).rotate_left(-1),
+                        "(cat (slice (const 9'd256) 1:9) (slice (const 9'd256) 0:1))")
+        self.assertRepr(Const(256).rotate_left(-7),
+                        "(cat (slice (const 9'd256) 7:9) (slice (const 9'd256) 0:7))")
+
+    def test_rotate_left_wrong(self):
+        with self.assertRaises(TypeError,
+                msg="Rotate amount must be an integer, not 'str'"):
+            Const(31).rotate_left("str")
+
+    def test_rotate_right(self):
+        self.assertRepr(Const(256).rotate_right(1),
+                        "(cat (slice (const 9'd256) 1:9) (slice (const 9'd256) 0:1))")
+        self.assertRepr(Const(256).rotate_right(7),
+                        "(cat (slice (const 9'd256) 7:9) (slice (const 9'd256) 0:7))")
+        self.assertRepr(Const(256).rotate_right(-1),
+                        "(cat (slice (const 9'd256) 8:9) (slice (const 9'd256) 0:8))")
+        self.assertRepr(Const(256).rotate_right(-7),
+                        "(cat (slice (const 9'd256) 2:9) (slice (const 9'd256) 0:2))")
+
+    def test_rotate_right_wrong(self):
+        with self.assertRaises(TypeError,
+                msg="Rotate amount must be an integer, not 'str'"):
+            Const(31).rotate_right("str")
+
 
 class ConstTestCase(FHDLTestCase):
     def test_shape(self):
@@ -374,11 +476,11 @@ class OperatorTestCase(FHDLTestCase):
         self.assertEqual(v1.shape(), unsigned(11))
 
     def test_shl_wrong(self):
-        with self.assertRaises(NotImplementedError,
-                msg="Shift by a signed value is not supported"):
+        with self.assertRaises(TypeError,
+                msg="Shift amount must be unsigned"):
             1 << Const(0, signed(6))
-        with self.assertRaises(NotImplementedError,
-                msg="Shift by a signed value is not supported"):
+        with self.assertRaises(TypeError,
+                msg="Shift amount must be unsigned"):
             Const(1, unsigned(4)) << -1
 
     def test_shr(self):
@@ -387,11 +489,11 @@ class OperatorTestCase(FHDLTestCase):
         self.assertEqual(v1.shape(), unsigned(4))
 
     def test_shr_wrong(self):
-        with self.assertRaises(NotImplementedError,
-                msg="Shift by a signed value is not supported"):
+        with self.assertRaises(TypeError,
+                msg="Shift amount must be unsigned"):
             1 << Const(0, signed(6))
-        with self.assertRaises(NotImplementedError,
-                msg="Shift by a signed value is not supported"):
+        with self.assertRaises(TypeError,
+                msg="Shift amount must be unsigned"):
             Const(1, unsigned(4)) << -1
 
     def test_lt(self):
@@ -672,13 +774,13 @@ class ArrayTestCase(FHDLTestCase):
         v1 = a[s1]
         v2 = a[s2]
         with self.assertRaisesRegex(ValueError,
-                regex=r"^Array can no longer be mutated after it was indexed with a value at "):
+                r"^Array can no longer be mutated after it was indexed with a value at "):
             a[1] = 2
         with self.assertRaisesRegex(ValueError,
-                regex=r"^Array can no longer be mutated after it was indexed with a value at "):
+                r"^Array can no longer be mutated after it was indexed with a value at "):
             del a[1]
         with self.assertRaisesRegex(ValueError,
-                regex=r"^Array can no longer be mutated after it was indexed with a value at "):
+                r"^Array can no longer be mutated after it was indexed with a value at "):
             a.insert(1, 2)
 
     def test_repr(self):
@@ -891,6 +993,14 @@ class UserValueTestCase(FHDLTestCase):
         self.assertEqual(uv.shape(), unsigned(1))
         self.assertEqual(uv.lower_count, 1)
 
+    def test_lower_to_user_value(self):
+        uv = MockUserValue(MockUserValue(1))
+        self.assertEqual(uv.shape(), unsigned(1))
+        self.assertIsInstance(uv.shape(), Shape)
+        uv.lowered = MockUserValue(2)
+        self.assertEqual(uv.shape(), unsigned(1))
+        self.assertEqual(uv.lower_count, 1)
+
 
 class SampleTestCase(FHDLTestCase):
     def test_const(self):