Repository: amaranth-lang/amaranth
Pull request #1479 (2024-08-10 20:22:52)

hdl._ast: name Formatter instance uniquely. [0.5 backport]
Backport of #1478.

whitequark: Thanks!

Patch:
diff --git a/amaranth/hdl/_ast.py b/amaranth/hdl/_ast.py
index 53d6971..731b5fa 100644
--- a/amaranth/hdl/_ast.py
+++ b/amaranth/hdl/_ast.py
@@ -2556,7 +2556,7 @@ class _FormatLike:
 @final
 class Format(_FormatLike):
     def __init__(self, format, *args, **kwargs):
-        fmt = string.Formatter()
+        fmtter = string.Formatter()
         chunks = []
         used_args = set()
         auto_arg_index = 0
@@ -2577,29 +2577,29 @@ class Format(_FormatLike):
                                         "specification")
                 auto_arg_index = None
 
-            obj, arg_used = fmt.get_field(field_name, args, kwargs)
+            obj, arg_used = fmtter.get_field(field_name, args, kwargs)
             used_args.add(arg_used)
             return obj
 
         def subformat(sub_string):
             result = []
-            for literal, field_name, format_spec, conversion in fmt.parse(sub_string):
+            for literal, field_name, format_spec, conversion in fmtter.parse(sub_string):
                 result.append(literal)
                 if field_name is not None:
                     obj = get_field(field_name)
-                    obj = fmt.convert_field(obj, conversion)
+                    obj = fmtter.convert_field(obj, conversion)
                     format_spec = subformat(format_spec)
-                    result.append(fmt.format_field(obj, format_spec))
+                    result.append(fmtter.format_field(obj, format_spec))
             return "".join(result)
 
-        for literal, field_name, format_spec, conversion in fmt.parse(format):
+        for literal, field_name, format_spec, conversion in fmtter.parse(format):
             chunks.append(literal)
             if field_name is not None:
                 obj = get_field(field_name)
                 if conversion == "v":
                     obj = Value.cast(obj)
                 else:
-                    obj = fmt.convert_field(obj, conversion)
+                    obj = fmtter.convert_field(obj, conversion)
                 format_spec = subformat(format_spec)
                 if isinstance(obj, Value):
                     # Perform validation.
@@ -2621,7 +2621,7 @@ class Format(_FormatLike):
                         raise ValueError(f"Format specifiers ({format_spec!r}) cannot be used for 'Format' objects")
                     chunks += obj._as_format()._chunks
                 else:
-                    chunks.append(fmt.format_field(obj, format_spec))
+                    chunks.append(fmtter.format_field(obj, format_spec))
 
         for i in range(len(args)):
             if i not in used_args:


Test patch:
diff --git a/tests/test_sim.py b/tests/test_sim.py
index e3a6a12..a75cd50 100644
--- a/tests/test_sim.py
+++ b/tests/test_sim.py
@@ -1274,6 +1274,33 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
             [unknown]
         """))
 
+    def test_print_enum_followed_by(self):
+        class MyEnum(enum.Enum, shape=unsigned(2)):
+            A = 0
+            B = 1
+            CDE = 2
+
+        sig = Signal(MyEnum)
+        ctr = Signal(2)
+        m = Module()
+        m.d.comb += sig.eq(ctr)
+        m.d.sync += [
+            Print(Format("{} {}", sig, ctr)),
+            ctr.eq(ctr + 1),
+        ]
+        output = StringIO()
+        with redirect_stdout(output):
+            with self.assertSimulation(m) as sim:
+                sim.add_clock(1e-6, domain="sync")
+                async def testbench(ctx):
+                    await ctx.tick().repeat(4)
+                sim.add_testbench(testbench)
+        self.assertEqual(output.getvalue(), dedent("""\
+            A 0
+            B 1
+            CDE 2
+            [unknown] 3
+        """))
 
     def test_assert(self):
         m = Module()