Repository: jeremiah-c-leary/vhdl-style-guide (language: python)

Issue:
Add whitespace rules for package instantiation declarations
Subtask of #1306. Implement whitespace rules for package instantiation declarations.

For example, rules to fix this
```vhdl
package        my_pkg        is        new        my_generic_pkg
  generic map (
    g_my_generic => 2
  );
```
to this
```vhdl
package my_pkg is new my_generic_pkg
  generic map (
    g_my_generic => 2
  );
```
Rule for case in hexadecimal constants and base specifier
**Is your feature request related to a problem? Please describe.**
Our coding guideline prescribes upper case for letters in hexadecimal numeric constants and lower case for the "x" before the hex string. I cannot find a rule that allows enforcing this:

Before:
`constant c : std_logic_vector(31 downto 0) := X"cafebabe";`

Required after:
`constant c : std_logic_vector(31 downto 0) := x"CAFEBABE";`

**Describe the solution you'd like**
Add a rule that allows enforcing the case of letters in hexadecimal numeric constants (`extended_digit`) and, separately, the `base_specifier`.


Discussion / hints:

Hi @thgbe. I've had a go at fulfilling your request. I still need to work on it a bit more to pass all of the CI tests, but in the meantime, could you please check whether this branch https://github.com/JHertz5/vhdl-style-guide/tree/issue-1236 works for you?

Update: I've finished tidying the branch,  it should be ready now.
Thank you very much for the quick implementation @JHertz5! I tried you branch, and it works nicely for me.

Fix patch:
diff --git a/docs/configuring_whitespace_rules.rst b/docs/configuring_whitespace_rules.rst
index de5c278ef..8a96a1ca4 100644
--- a/docs/configuring_whitespace_rules.rst
+++ b/docs/configuring_whitespace_rules.rst
@@ -218,6 +218,10 @@ Rules Enforcing Whitespace
 * `package_009 <package_rules.html#package-009>`_
 * `package_body_100 <package_body_rules.html#package-body-100>`_
 * `package_body_101 <package_body_rules.html#package-body-101>`_
+* `package_instantiation_100 <package_instantiation_rules.html#package-instantiation-100>`_
+* `package_instantiation_101 <package_instantiation_rules.html#package-instantiation-101>`_
+* `package_instantiation_102 <package_instantiation_rules.html#package-instantiation-102>`_
+* `package_instantiation_103 <package_instantiation_rules.html#package-instantiation-103>`_
 * `port_003 <port_rules.html#port-003>`_
 * `port_020 <port_rules.html#port-020>`_
 * `port_100 <port_rules.html#port-100>`_
diff --git a/docs/package_instantiation_rules.rst b/docs/package_instantiation_rules.rst
index 5bd44043a..f84f04f4f 100644
--- a/docs/package_instantiation_rules.rst
+++ b/docs/package_instantiation_rules.rst
@@ -79,6 +79,90 @@ This rule checks the uninstantiated package name is on the same line as the **ne
 
 **Fix**
 
+.. code-block:: vhdl
+
+   package my_pkg is new my_generic_pkg
+
+package_instantiation_100
+#########################
+
+|phase_2| |error| |whitespace|
+
+This rule checks for a single space between the **package** keyword and the new package identifier.
+
+|configuring_whitespace_rules_link|
+
+**Violation**
+
+.. code-block:: vhdl
+
+   package    my_pkg is new my_generic_pkg
+
+**Fix**
+
+.. code-block:: vhdl
+
+   package my_pkg is new my_generic_pkg
+
+package_instantiation_101
+#########################
+
+|phase_2| |error| |whitespace|
+
+This rule checks for a single space between the new package identifier and the **is** keyword.
+
+|configuring_whitespace_rules_link|
+
+**Violation**
+
+.. code-block:: vhdl
+
+   package my_pkg    is new my_generic_pkg
+
+**Fix**
+
+.. code-block:: vhdl
+
+   package my_pkg is new my_generic_pkg
+
+package_instantiation_102
+#########################
+
+|phase_2| |error| |whitespace|
+
+This rule checks for a single space between the **is** keyword and the **new** keyword.
+
+|configuring_whitespace_rules_link|
+
+**Violation**
+
+.. code-block:: vhdl
+
+   package my_pkg is    new my_generic_pkg
+
+**Fix**
+
+.. code-block:: vhdl
+
+   package my_pkg is new my_generic_pkg
+
+package_instantiation_103
+#########################
+
+|phase_2| |error| |whitespace|
+
+This rule checks for a single space between **new** keyword and the uninstantiated package name.
+
+|configuring_whitespace_rules_link|
+
+**Violation**
+
+.. code-block:: vhdl
+
+   package my_pkg is new    my_generic_pkg
+
+**Fix**
+
 .. code-block:: vhdl
 
    package my_pkg is new my_generic_pkg
diff --git a/docs/rule_groups/whitespace_rule_group.rst b/docs/rule_groups/whitespace_rule_group.rst
index 3201d98d9..304096414 100644
--- a/docs/rule_groups/whitespace_rule_group.rst
+++ b/docs/rule_groups/whitespace_rule_group.rst
@@ -112,6 +112,10 @@ Rules Enforcing Whitespace Rule Group
 * `package_009 <../package_rules.html#package-009>`_
 * `package_body_100 <../package_body_rules.html#package-body-100>`_
 * `package_body_101 <../package_body_rules.html#package-body-101>`_
+* `package_instantiation_100 <../package_instantiation_rules.html#package-instantiation-100>`_
+* `package_instantiation_101 <../package_instantiation_rules.html#package-instantiation-101>`_
+* `package_instantiation_102 <../package_instantiation_rules.html#package-instantiation-102>`_
+* `package_instantiation_103 <../package_instantiation_rules.html#package-instantiation-103>`_
 * `port_003 <../port_rules.html#port-003>`_
 * `port_007 <../port_rules.html#port-007>`_
 * `port_008 <../port_rules.html#port-008>`_
diff --git a/vsg/rules/package_instantiation/__init__.py b/vsg/rules/package_instantiation/__init__.py
index b8b687b44..63e99821f 100644
--- a/vsg/rules/package_instantiation/__init__.py
+++ b/vsg/rules/package_instantiation/__init__.py
@@ -4,6 +4,10 @@
 from .rule_002 import rule_002
 from .rule_003 import rule_003
 from .rule_004 import rule_004
+from .rule_100 import rule_100
+from .rule_101 import rule_101
+from .rule_102 import rule_102
+from .rule_103 import rule_103
 from .rule_500 import rule_500
 from .rule_501 import rule_501
 from .rule_502 import rule_502
diff --git a/vsg/rules/package_instantiation/rule_100.py b/vsg/rules/package_instantiation/rule_100.py
new file mode 100644
index 000000000..dd0277d14
--- /dev/null
+++ b/vsg/rules/package_instantiation/rule_100.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+
+from vsg import token
+from vsg.rules.whitespace_between_token_pairs import Rule
+
+lTokens = []
+lTokens.append([token.package_instantiation_declaration.package_keyword, token.identifier.identifier])
+
+
+class rule_100(Rule):
+    """
+    This rule checks for a single space between the **package** keyword and the new package identifier.
+
+    |configuring_whitespace_rules_link|
+
+    **Violation**
+
+    .. code-block:: vhdl
+
+       package    my_pkg is new my_generic_pkg
+
+    **Fix**
+
+    .. code-block:: vhdl
+
+       package my_pkg is new my_generic_pkg
+    """
+
+    def __init__(self):
+        super().__init__(lTokens)
diff --git a/vsg/rules/package_instantiation/rule_101.py b/vsg/rules/package_instantiation/rule_101.py
new file mode 100644
index 000000000..57c2fbb62
--- /dev/null
+++ b/vsg/rules/package_instantiation/rule_101.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+
+from vsg import token
+from vsg.rules.whitespace_between_token_pairs import Rule
+
+lTokens = []
+lTokens.append([token.identifier.identifier, token.package_instantiation_declaration.is_keyword])
+
+
+class rule_101(Rule):
+    """
+    This rule checks for a single space between the new package identifier and the **is** keyword.
+
+    |configuring_whitespace_rules_link|
+
+    **Violation**
+
+    .. code-block:: vhdl
+
+       package my_pkg    is new my_generic_pkg
+
+    **Fix**
+
+    .. code-block:: vhdl
+
+       package my_pkg is new my_generic_pkg
+    """
+
+    def __init__(self):
+        super().__init__(lTokens)
diff --git a/vsg/rules/package_instantiation/rule_102.py b/vsg/rules/package_instantiation/rule_102.py
new file mode 100644
index 000000000..f4ccaf9cc
--- /dev/null
+++ b/vsg/rules/package_instantiation/rule_102.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+
+from vsg import token
+from vsg.rules.whitespace_between_token_pairs import Rule
+
+lTokens = []
+lTokens.append([token.package_instantiation_declaration.is_keyword, token.package_instantiation_declaration.new_keyword])
+
+
+class rule_102(Rule):
+    """
+    This rule checks for a single space between the **is** keyword and the **new** keyword.
+
+    |configuring_whitespace_rules_link|
+
+    **Violation**
+
+    .. code-block:: vhdl
+
+       package my_pkg is    new my_generic_pkg
+
+    **Fix**
+
+    .. code-block:: vhdl
+
+       package my_pkg is new my_generic_pkg
+    """
+
+    def __init__(self):
+        super().__init__(lTokens)
diff --git a/vsg/rules/package_instantiation/rule_103.py b/vsg/rules/package_instantiation/rule_103.py
new file mode 100644
index 000000000..7f23a3667
--- /dev/null
+++ b/vsg/rules/package_instantiation/rule_103.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+
+from vsg import token
+from vsg.rules.whitespace_between_token_pairs import Rule
+
+lTokens = []
+lTokens.append([token.package_instantiation_declaration.new_keyword, token.package_instantiation_declaration.uninstantiated_package_name])
+
+
+class rule_103(Rule):
+    """
+    This rule checks for a single space between **new** keyword and the uninstantiated package name.
+
+    |configuring_whitespace_rules_link|
+
+    **Violation**
+
+    .. code-block:: vhdl
+
+       package my_pkg is new    my_generic_pkg
+
+    **Fix**
+
+    .. code-block:: vhdl
+
+       package my_pkg is new my_generic_pkg
+    """
+
+    def __init__(self):
+        super().__init__(lTokens)


Test patch:
diff --git a/tests/package_instantiation/rule_100_test_input.fixed.vhd b/tests/package_instantiation/rule_100_test_input.fixed.vhd
new file mode 100644
index 000000000..56c16497f
--- /dev/null
+++ b/tests/package_instantiation/rule_100_test_input.fixed.vhd
@@ -0,0 +1,10 @@
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
diff --git a/tests/package_instantiation/rule_100_test_input.vhd b/tests/package_instantiation/rule_100_test_input.vhd
new file mode 100644
index 000000000..0c73bd403
--- /dev/null
+++ b/tests/package_instantiation/rule_100_test_input.vhd
@@ -0,0 +1,10 @@
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
+
+package     my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
diff --git a/tests/package_instantiation/rule_101_test_input.fixed.vhd b/tests/package_instantiation/rule_101_test_input.fixed.vhd
new file mode 100644
index 000000000..56c16497f
--- /dev/null
+++ b/tests/package_instantiation/rule_101_test_input.fixed.vhd
@@ -0,0 +1,10 @@
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
diff --git a/tests/package_instantiation/rule_101_test_input.vhd b/tests/package_instantiation/rule_101_test_input.vhd
new file mode 100644
index 000000000..e8b4d1b66
--- /dev/null
+++ b/tests/package_instantiation/rule_101_test_input.vhd
@@ -0,0 +1,10 @@
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
+
+package my_pkg     is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
diff --git a/tests/package_instantiation/rule_102_test_input.fixed.vhd b/tests/package_instantiation/rule_102_test_input.fixed.vhd
new file mode 100644
index 000000000..56c16497f
--- /dev/null
+++ b/tests/package_instantiation/rule_102_test_input.fixed.vhd
@@ -0,0 +1,10 @@
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
diff --git a/tests/package_instantiation/rule_102_test_input.vhd b/tests/package_instantiation/rule_102_test_input.vhd
new file mode 100644
index 000000000..aa080bc4c
--- /dev/null
+++ b/tests/package_instantiation/rule_102_test_input.vhd
@@ -0,0 +1,10 @@
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
+
+package my_pkg is     new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
diff --git a/tests/package_instantiation/rule_103_test_input.fixed.vhd b/tests/package_instantiation/rule_103_test_input.fixed.vhd
new file mode 100644
index 000000000..56c16497f
--- /dev/null
+++ b/tests/package_instantiation/rule_103_test_input.fixed.vhd
@@ -0,0 +1,10 @@
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
diff --git a/tests/package_instantiation/rule_103_test_input.vhd b/tests/package_instantiation/rule_103_test_input.vhd
new file mode 100644
index 000000000..37a676e2f
--- /dev/null
+++ b/tests/package_instantiation/rule_103_test_input.vhd
@@ -0,0 +1,10 @@
+
+package my_pkg is new my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
+
+package my_pkg is new     my_generic_pkg
+  generic map (
+    g_my_generic => 2
+  );
diff --git a/tests/package_instantiation/test_rule_100.py b/tests/package_instantiation/test_rule_100.py
new file mode 100644
index 000000000..86ed65f58
--- /dev/null
+++ b/tests/package_instantiation/test_rule_100.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+
+import os
+import unittest
+
+from tests import utils
+from vsg import vhdlFile
+from vsg.rules import package_instantiation
+
+sTestDir = os.path.dirname(__file__)
+
+lFile, eError = vhdlFile.utils.read_vhdlfile(os.path.join(sTestDir, "rule_100_test_input.vhd"))
+
+lExpected = []
+lExpected.append("")
+utils.read_file(os.path.join(sTestDir, "rule_100_test_input.fixed.vhd"), lExpected)
+
+
+class test_package_instantiation_rule(unittest.TestCase):
+    def setUp(self):
+        self.oFile = vhdlFile.vhdlFile(lFile)
+        self.assertIsNone(eError)
+
+    def test_rule_100(self):
+        oRule = package_instantiation.rule_100()
+        self.assertTrue(oRule)
+        self.assertEqual(oRule.name, "package_instantiation")
+        self.assertEqual(oRule.identifier, "100")
+
+        lExpected = [7]
+
+        oRule.analyze(self.oFile)
+        self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations))
+
+    def test_fix_rule_100(self):
+        oRule = package_instantiation.rule_100()
+
+        oRule.fix(self.oFile)
+
+        lActual = self.oFile.get_lines()
+
+        self.assertEqual(lExpected, lActual)
+
+        oRule.analyze(self.oFile)
+        self.assertEqual(oRule.violations, [])
diff --git a/tests/package_instantiation/test_rule_101.py b/tests/package_instantiation/test_rule_101.py
new file mode 100644
index 000000000..e9cb7aeff
--- /dev/null
+++ b/tests/package_instantiation/test_rule_101.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+
+import os
+import unittest
+
+from tests import utils
+from vsg import vhdlFile
+from vsg.rules import package_instantiation
+
+sTestDir = os.path.dirname(__file__)
+
+lFile, eError = vhdlFile.utils.read_vhdlfile(os.path.join(sTestDir, "rule_101_test_input.vhd"))
+
+lExpected = []
+lExpected.append("")
+utils.read_file(os.path.join(sTestDir, "rule_101_test_input.fixed.vhd"), lExpected)
+
+
+class test_package_instantiation_rule(unittest.TestCase):
+    def setUp(self):
+        self.oFile = vhdlFile.vhdlFile(lFile)
+        self.assertIsNone(eError)
+
+    def test_rule_101(self):
+        oRule = package_instantiation.rule_101()
+        self.assertTrue(oRule)
+        self.assertEqual(oRule.name, "package_instantiation")
+        self.assertEqual(oRule.identifier, "101")
+
+        lExpected = [7]
+
+        oRule.analyze(self.oFile)
+        self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations))
+
+    def test_fix_rule_101(self):
+        oRule = package_instantiation.rule_101()
+
+        oRule.fix(self.oFile)
+
+        lActual = self.oFile.get_lines()
+
+        self.assertEqual(lExpected, lActual)
+
+        oRule.analyze(self.oFile)
+        self.assertEqual(oRule.violations, [])
diff --git a/tests/package_instantiation/test_rule_102.py b/tests/package_instantiation/test_rule_102.py
new file mode 100644
index 000000000..2c69b625d
--- /dev/null
+++ b/tests/package_instantiation/test_rule_102.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+
+import os
+import unittest
+
+from tests import utils
+from vsg import vhdlFile
+from vsg.rules import package_instantiation
+
+sTestDir = os.path.dirname(__file__)
+
+lFile, eError = vhdlFile.utils.read_vhdlfile(os.path.join(sTestDir, "rule_102_test_input.vhd"))
+
+lExpected = []
+lExpected.append("")
+utils.read_file(os.path.join(sTestDir, "rule_102_test_input.fixed.vhd"), lExpected)
+
+
+class test_package_instantiation_rule(unittest.TestCase):
+    def setUp(self):
+        self.oFile = vhdlFile.vhdlFile(lFile)
+        self.assertIsNone(eError)
+
+    def test_rule_102(self):
+        oRule = package_instantiation.rule_102()
+        self.assertTrue(oRule)
+        self.assertEqual(oRule.name, "package_instantiation")
+        self.assertEqual(oRule.identifier, "102")
+
+        lExpected = [7]
+
+        oRule.analyze(self.oFile)
+        self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations))
+
+    def test_fix_rule_102(self):
+        oRule = package_instantiation.rule_102()
+
+        oRule.fix(self.oFile)
+
+        lActual = self.oFile.get_lines()
+
+        self.assertEqual(lExpected, lActual)
+
+        oRule.analyze(self.oFile)
+        self.assertEqual(oRule.violations, [])
diff --git a/tests/package_instantiation/test_rule_103.py b/tests/package_instantiation/test_rule_103.py
new file mode 100644
index 000000000..ea1bac9c4
--- /dev/null
+++ b/tests/package_instantiation/test_rule_103.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+
+import os
+import unittest
+
+from tests import utils
+from vsg import vhdlFile
+from vsg.rules import package_instantiation
+
+sTestDir = os.path.dirname(__file__)
+
+lFile, eError = vhdlFile.utils.read_vhdlfile(os.path.join(sTestDir, "rule_103_test_input.vhd"))
+
+lExpected = []
+lExpected.append("")
+utils.read_file(os.path.join(sTestDir, "rule_103_test_input.fixed.vhd"), lExpected)
+
+
+class test_package_instantiation_rule(unittest.TestCase):
+    def setUp(self):
+        self.oFile = vhdlFile.vhdlFile(lFile)
+        self.assertIsNone(eError)
+
+    def test_rule_103(self):
+        oRule = package_instantiation.rule_103()
+        self.assertTrue(oRule)
+        self.assertEqual(oRule.name, "package_instantiation")
+        self.assertEqual(oRule.identifier, "103")
+
+        lExpected = [7]
+
+        oRule.analyze(self.oFile)
+        self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations))
+
+    def test_fix_rule_103(self):
+        oRule = package_instantiation.rule_103()
+
+        oRule.fix(self.oFile)
+
+        lActual = self.oFile.get_lines()
+
+        self.assertEqual(lExpected, lActual)
+
+        oRule.analyze(self.oFile)
+        self.assertEqual(oRule.violations, [])