hdl.{ast,dsl}: allow whitespace in bit patterns.
authorwhitequark <whitequark@whitequark.org>
Tue, 4 Feb 2020 07:54:54 +0000 (07:54 +0000)
committerwhitequark <whitequark@whitequark.org>
Tue, 4 Feb 2020 07:54:54 +0000 (07:54 +0000)
Fixes #316.

nmigen/hdl/ast.py
nmigen/hdl/dsl.py
nmigen/test/test_hdl_ast.py
nmigen/test/test_hdl_dsl.py

index 2c039d12cb4d6d7fc592e9ea6552d0858c72b527..96f1e307d53fedb7fd1de7b96b6502ba56a7d989 100644 (file)
@@ -357,11 +357,12 @@ class Value(metaclass=ABCMeta):
                 raise SyntaxError("Match pattern must be an integer, a string, or an enumeration, "
                                   "not {!r}"
                                   .format(pattern))
-            if isinstance(pattern, str) and any(bit not in "01-" for bit in pattern):
+            if isinstance(pattern, str) and any(bit not in "01- \t" for bit in pattern):
                 raise SyntaxError("Match pattern '{}' must consist of 0, 1, and - (don't care) "
-                                  "bits"
+                                  "bits, and may include whitespace"
                                   .format(pattern))
-            if isinstance(pattern, str) and len(pattern) != len(self):
+            if (isinstance(pattern, str) and
+                    len("".join(pattern.split())) != len(self)):
                 raise SyntaxError("Match pattern '{}' must have the same width as match value "
                                   "(which is {})"
                                   .format(pattern, len(self)))
@@ -372,6 +373,7 @@ class Value(metaclass=ABCMeta):
                               SyntaxWarning, stacklevel=3)
                 continue
             if isinstance(pattern, str):
+                pattern = "".join(pattern.split()) # remove whitespace
                 mask    = int(pattern.replace("0", "1").replace("-", "0"), 2)
                 pattern = int(pattern.replace("-", "0"), 2)
                 matches.append((self & mask) == pattern)
@@ -1300,7 +1302,7 @@ class Switch(Statement):
             new_keys = ()
             for key in keys:
                 if isinstance(key, str):
-                    pass
+                    key = "".join(key.split()) # remove whitespace
                 elif isinstance(key, int):
                     key = format(key, "b").rjust(len(self.test), "0")
                 elif isinstance(key, Enum):
index 247e07ef9bb0bf00118167704e6a61259f819809..83637374e22d5ab898dffa94d295f8f5496836ae 100644 (file)
@@ -301,10 +301,12 @@ class Module(_ModuleBuilderRoot, Elaboratable):
                 raise SyntaxError("Case pattern must be an integer, a string, or an enumeration, "
                                   "not {!r}"
                                   .format(pattern))
-            if isinstance(pattern, str) and any(bit not in "01-" for bit in pattern):
-                raise SyntaxError("Case pattern '{}' must consist of 0, 1, and - (don't care) bits"
+            if isinstance(pattern, str) and any(bit not in "01- \t" for bit in pattern):
+                raise SyntaxError("Case pattern '{}' must consist of 0, 1, and - (don't care) "
+                                  "bits, and may include whitespace"
                                   .format(pattern))
-            if isinstance(pattern, str) and len(pattern) != len(switch_data["test"]):
+            if (isinstance(pattern, str) and
+                    len("".join(pattern.split())) != len(switch_data["test"])):
                 raise SyntaxError("Case pattern '{}' must have the same width as switch value "
                                   "(which is {})"
                                   .format(pattern, len(switch_data["test"])))
index 76665ccfbf80118927f4a5e8530c081da83ad777..2a40e8b88851677224c946c14900bce194028100 100644 (file)
@@ -464,6 +464,9 @@ class OperatorTestCase(FHDLTestCase):
         self.assertRepr(s.matches("10--"), """
         (== (& (sig s) (const 4'd12)) (const 4'd8))
         """)
+        self.assertRepr(s.matches("1 0--"), """
+        (== (& (sig s) (const 4'd12)) (const 4'd8))
+        """)
 
     def test_matches_enum(self):
         s = Signal(SignedEnum)
@@ -484,7 +487,8 @@ class OperatorTestCase(FHDLTestCase):
     def test_matches_bits_wrong(self):
         s = Signal(4)
         with self.assertRaises(SyntaxError,
-                msg="Match pattern 'abc' must consist of 0, 1, and - (don't care) bits"):
+                msg="Match pattern 'abc' must consist of 0, 1, and - (don't care) bits, "
+                    "and may include whitespace"):
             s.matches("abc")
 
     def test_matches_pattern_wrong(self):
index 7573941d166acb5a41c99d4e3737546655353364..cc8467c87a6e6c5ee509db38e0d3a4c55854337b 100644 (file)
@@ -331,12 +331,15 @@ class DSLTestCase(FHDLTestCase):
                 m.d.comb += self.c1.eq(1)
             with m.Case("11--"):
                 m.d.comb += self.c2.eq(1)
+            with m.Case("1 0--"):
+                m.d.comb += self.c2.eq(1)
         m._flush()
         self.assertRepr(m._statements, """
         (
             (switch (sig w1)
                 (case 0011 (eq (sig c1) (const 1'd1)))
                 (case 11-- (eq (sig c2) (const 1'd1)))
+                (case 10-- (eq (sig c2) (const 1'd1)))
             )
         )
         """)
@@ -435,7 +438,8 @@ class DSLTestCase(FHDLTestCase):
         m = Module()
         with m.Switch(self.w1):
             with self.assertRaises(SyntaxError,
-                    msg="Case pattern 'abc' must consist of 0, 1, and - (don't care) bits"):
+                    msg="Case pattern 'abc' must consist of 0, 1, and - (don't care) bits, "
+                        "and may include whitespace"):
                 with m.Case("abc"):
                     pass