From 8c6bb8918adbece06be9c941d186e25cc678897e Mon Sep 17 00:00:00 2001
From: donker <donker@astron.nl>
Date: Mon, 1 May 2023 08:34:48 +0200
Subject: [PATCH] RTSD-79, add vhdl_style script

---
 vhdl_style_fix.py | 217 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 217 insertions(+)
 create mode 100755 vhdl_style_fix.py

diff --git a/vhdl_style_fix.py b/vhdl_style_fix.py
new file mode 100755
index 0000000000..84ac58002c
--- /dev/null
+++ b/vhdl_style_fix.py
@@ -0,0 +1,217 @@
+#!/usr/bin/python3
+from collections import OrderedDict
+from argparse import ArgumentParser, RawTextHelpFormatter
+from textwrap import dedent
+from copy import copy
+
+
+def main():
+    with open(args.filename, 'r') as fd:
+        old_data = fd.read()
+
+    parse = ParseData(old_data)
+    parse.parse()
+    new_data = parse.get_data()
+    
+    if old_data != new_data:
+        print(f"fix {args.filename}")
+        with open(args.filename, 'w') as fd:
+            fd.write(new_data)
+
+
+class ParseData:
+    def __init__(self, data):
+        self.types = Types()
+        self.operators = Operators()
+        self.reserved_words = ReservedWords()
+
+        self._comment = False
+        self._block_begin = ['--'] #, 'entity', 'generic', 'port', 'architecture']
+        self._block_end = [');', 'end']
+        self._data = data
+        self._new_data = []
+        self._last_ch = ''
+        self._word = ''
+        self._operator = ''
+        self._is_block_word = False
+        self._blocks = []
+        self._last_block = 'empty'
+        self._indent = 0
+
+    def get_data(self):
+        return ''.join(self._new_data)
+    
+    # handle _word
+    def add_to_word(self, ch):
+        self._word += ch
+        self._is_block_word = self._word in self._block_begin
+
+    def get_word(self):
+        return self._word
+
+    def clear_word(self):
+        self._word = ''
+        self._is_block_word = False
+
+    def is_block_word(self):
+        return self._is_block_word
+
+    # handle _operator
+    def add_to_operator(self, ch):
+        self._operator += ch
+
+    def get_operator(self):
+        return self._operator
+
+    def clear_operator(self):
+        self._operator = ''
+
+    # handle _blocks info
+    def add_block(self, block):
+        self._blocks.append(block)
+        self._last_block = block
+
+    def delete_last_block(self):
+        self._blocks.pop()
+        try:
+            self._last_block = self._blocks[-1]
+        except IndexError:
+            self._last_block = 'empty'
+
+    def last_block(self):
+        return self._last_block
+
+    # handle new_data
+    def add_new_data(self, word):
+        for ch in word:
+            self._new_data.append(ch)
+
+    # parse data
+    def parse(self):
+        for ch in self._data:
+                
+            # '--' is comment
+            if self._comment is True:
+                if ch == "\n":
+                    self._comment = False
+                self.add_new_data(ch)
+                continue
+            
+            # if ch == "\n":
+            #     self.add_new_data("\n")
+            #     continue
+
+            if self.get_operator() and (ch.isidentifier() or ch.isspace()):
+                self.add_new_data(self.get_operator())
+                self.clear_operator()
+
+            if ch.isidentifier():
+                self.add_to_word(ch)
+                continue
+
+            if self.get_word():
+                if self.types.is_valid(self.get_word()):  # check if in types
+                    self.add_new_data(self.get_word().lower())
+                elif self.operators.is_valid(self.get_word()):  # check if in operators
+                    self.add_new_data(self.get_word().lower())
+                elif self.reserved_words.is_valid(self.get_word()):  # check if in reserved words
+                    self.add_new_data(self.get_word().lower())
+                else:
+                    self.add_new_data(self.get_word())
+                self.clear_word()
+
+            if self.operators.is_valid(ch):
+                self.add_to_operator(ch)
+                if self.get_operator() == '--':
+                    self.add_new_data(self.get_operator())
+                    self.clear_operator()
+                    self._comment = True
+                continue
+            
+            if self.get_operator():
+                self.add_new_data(self.get_operator())
+                self.clear_operator()
+
+            self.add_new_data(ch)
+
+            if self.is_block_word():
+                self.add_block(self.get_word())
+                continue
+
+
+class Entity:
+    """
+    entity [name] is
+      generic (
+        [g_*] : [type] := [val]; -- info
+        [g_*] : [type] := [val] -- info
+      );
+      port (
+        [port] : [dir] [type] := [val];
+        [port] : [dir] [type] := [val]
+      );
+    end [name];
+    """
+    def __init__(self):
+        pass
+
+
+class Types:
+    def __init__(self):
+        self.types = ["bit", "bit_vector", "integer", "natural", "positive", "boolean", "string",
+                      "character", "real", "time", "delay_length",
+                      "std_ulogic", "std_ulogic_vector", "std_logic", "std_logic_vector"]
+    
+    def is_valid(self, val):
+        if val.lower() in self.types:
+            return True
+        return False
+
+
+class Operators:
+    def __init__(self):
+        self.operators = ["**", "abs", "not", "*", "/", "mod", "rem", "+", "-", "+", "-", "&",
+                          "sll", "srl", "sla", "sra", "rol", "ror", "=", "/=", "<", "<=", ">",
+                          ">=", "and", "or", "nand", "nor", "xor", "xnor"]
+
+    def is_valid(self, val):
+        if val.lower() in self.operators:
+            return True
+        return False
+
+
+class ReservedWords:
+    def __init__(self):
+        self.reserved_words = ["abs", "access", "after", "alias", "all", "and", "architecture",
+                               "array", "assert", "attribute", "begin", "block", "body", "buffer",
+                               "bus", "case", "component", "configuration", "constant", "disconnect",
+                               "downto", "else", "elsif", "end", "entity", "exit", "file", "for",
+                               "function", "generate", "generic", "group", "guarded", "if", "impure",
+                               "in", "inertial", "inout", "is", "label", "library", "linkage", "literal",
+                               "loop", "map", "mod", "nand", "new", "next", "nor", "not", "null", "of",
+                               "on", "open", "or", "others", "out", "package", "port", "postponed",
+                               "procedure", "process", "pure", "range", "record", "register", "reject",
+                               "rem", "report", "return", "rol", "ror", "select", "severity", "signal",
+                               "shared", "sla", "sll", "sra", "srl", "subtype", "then", "to", "transport",
+                               "type", "unaffected", "units", "until", "use", "variable", "wait", "when",
+                               "while", "with", "xnor", "xor"]
+
+    def is_valid(self, val):
+        if val.lower() in self.reserved_words:
+            return True
+        return False
+
+
+if __name__ == "__main__":
+    # Parse command line arguments
+    parser = ArgumentParser(
+        description="".join(dedent("""\
+            vhdl style fixer:
+            * vhdl_style_fix.py filename -h
+            \n""")),
+        formatter_class=RawTextHelpFormatter)
+    parser.add_argument('filename', type=str, help="filename to fix")
+    parser.add_argument('-v', '--verbose', action='store_true', help="verbose output")
+    args = parser.parse_args()
+
+    main()
-- 
GitLab