From 827809845f21aa059a861ff3d0b101f6bfd60d95 Mon Sep 17 00:00:00 2001 From: michael-etzkorn Date: Sun, 24 Oct 2021 14:28:56 -0500 Subject: [PATCH 1/6] VHDL parser from andres manelli's fork for more entity parsing support --- hdlparse/vhdl_parser.py | 1370 +++++++++++++++++++++------------------ 1 file changed, 725 insertions(+), 645 deletions(-) diff --git a/hdlparse/vhdl_parser.py b/hdlparse/vhdl_parser.py index 029d9de..af9789d 100644 --- a/hdlparse/vhdl_parser.py +++ b/hdlparse/vhdl_parser.py @@ -6,721 +6,799 @@ import os import re from pprint import pprint - from hdlparse.minilexer import MiniLexer -"""VHDL documentation parser""" +'''VHDL documentation parser''' vhdl_tokens = { - 'root': [ - (r'package\s+(\w+)\s+is', 'package', 'package'), - (r'package\s+body\s+(\w+)\s+is', 'package_body', 'package_body'), - (r'function\s+(\w+|"[^"]+")\s*\(', 'function', 'param_list'), - (r'procedure\s+(\w+)\s*\(', 'procedure', 'param_list'), - (r'function\s+(\w+)', 'function', 'simple_func'), - (r'component\s+(\w+)\s*is', 'component', 'component'), - (r'entity\s+(\w+)\s*is', 'entity', 'entity'), - (r'architecture\s+(\w+)\s*of', 'architecture', 'architecture'), - (r'subtype\s+(\w+)\s+is\s+(\w+)', 'subtype'), - (r'type\s+(\w+)\s*is', 'type', 'type_decl'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'package': [ - (r'function\s+(\w+|"[^"]+")\s*\(', 'function', 'param_list'), - (r'procedure\s+(\w+)\s*\(', 'procedure', 'param_list'), - (r'function\s+(\w+)', 'function', 'simple_func'), - (r'component\s+(\w+)\s*is', 'component', 'component'), - (r'subtype\s+(\w+)\s+is\s+(\w+)', 'subtype'), - (r'constant\s+(\w+)\s+:\s+(\w+)', 'constant'), - (r'type\s+(\w+)\s*is', 'type', 'type_decl'), - (r'end\s+package', None, '#pop'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'package_body': [ - (r'end\s+package\s+body', None, '#pop'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'type_decl': [ - (r'array', 'array_type', '#pop'), - (r'file', 'file_type', '#pop'), - (r'access', 'access_type', '#pop'), - (r'record', 'record_type', '#pop'), - (r'range', 'range_type', '#pop'), - (r'\(', 'enum_type', '#pop'), - (r';', 'incomplete_type', '#pop'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'param_list': [ - (r'\s*((?:variable|signal|constant|file)\s+)?(\w+)\s*', 'param'), - (r'\s*,\s*', None), - (r'\s*:\s*', None, 'param_type'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'param_type': [ - (r'\s*((?:in|out|inout|buffer)\s+)?(\w+)\s*', 'param_type'), - (r'\s*;\s*', None, '#pop'), - (r"\s*:=\s*('.'|[^\s;)]+)", 'param_default'), - (r'\)\s*(?:return\s+(\w+)\s*)?;', 'end_subprogram', '#pop:2'), - (r'\)\s*(?:return\s+(\w+)\s*)?is', None, '#pop:2'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'simple_func': [ - (r'\s+return\s+(\w+)\s*;', 'end_subprogram', '#pop'), - (r'\s+return\s+(\w+)\s+is', None, '#pop'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'component': [ - (r'generic\s*\(', None, 'generic_list'), - (r'port\s*\(', None, 'port_list'), - (r'end\s+component\s*\w*;', 'end_component', '#pop'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'entity': [ - (r'end\s+entity\s*;', 'end_entity', '#pop'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'architecture': [ - (r'end\s+architecture\s*;', 'end_arch', '#pop'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'generic_list': [ - (r'\s*(\w+)\s*', 'generic_param'), - (r'\s*,\s*', None), - (r'\s*:\s*', None, 'generic_param_type'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'generic_param_type': [ - (r'\s*(\w+)\s*', 'generic_param_type'), - (r'\s*;\s*', None, '#pop'), - (r"\s*:=\s*([\w']+)", 'generic_param_default'), - (r'\)\s*;', 'end_generic', '#pop:2'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'port_list': [ - (r'\s*(\w+)\s*', 'port_param'), - (r'\s*,\s*', None), - (r'\s*:\s*', None, 'port_param_type'), - (r'--#\s*{{(.*)}}\n', 'section_meta'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'port_param_type': [ - (r'\s*(in|out|inout|buffer)\s+(\w+)\s*\(', 'port_array_param_type', 'array_range'), - (r'\s*(in|out|inout|buffer)\s+(\w+)\s*', 'port_param_type'), - (r'\s*;\s*', None, '#pop'), - (r"\s*:=\s*([\w']+)", 'port_param_default'), - (r'\)\s*;', 'end_port', '#pop:2'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'array_range': [ - (r'\(', 'open_paren', 'nested_parens'), - (r'\)', 'array_range_end', '#pop'), - ], - 'nested_parens': [ - (r'\(', 'open_paren', 'nested_parens'), - (r'\)', 'close_paren', '#pop'), - ], - 'block_comment': [ - (r'\*/', 'end_comment', '#pop'), - ], + 'root': [ + (r'package\s+(\w+)\s+is', 'package', 'package'), + (r'package\s+body\s+(\w+)\s+is', 'package_body', 'package_body'), + (r'function\s+(\w+|"[^"]+")\s*\(', 'function', 'param_list'), + (r'procedure\s+(\w+)\s*\(', 'procedure', 'param_list'), + (r'function\s+(\w+)', 'function', 'simple_func'), + (r'component\s+(\w+)\s*is', 'component', 'component'), + (r'entity\s+(\w+)\s*is', 'entity', 'entity'), + (r'architecture\s+(\w+)\s*of', 'architecture', 'architecture'), + (r'subtype\s+(\w+)\s+is\s+(\w+)', 'subtype'), + (r'type\s+(\w+)\s*is', 'type', 'type_decl'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'package': [ + (r'function\s+(\w+|"[^"]+")\s*\(', 'function', 'param_list'), + (r'procedure\s+(\w+)\s*\(', 'procedure', 'param_list'), + (r'function\s+(\w+)', 'function', 'simple_func'), + (r'component\s+(\w+)\s*is', 'component', 'component'), + (r'subtype\s+(\w+)\s+is\s+(\w+)', 'subtype'), + (r'constant\s+(\w+)\s+:\s+(\w+)', 'constant'), + (r'type\s+(\w+)\s*is', 'type', 'type_decl'), + (r'end\s+\w+\s*;', None, '#pop'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'package_body': [ + (r'end\s+\w+\s*;', None, '#pop'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'type_decl': [ + (r'array', 'array_type', '#pop'), + (r'file', 'file_type', '#pop'), + (r'access', 'access_type', '#pop'), + (r'record', 'record_type', '#pop'), + (r'range', 'range_type', '#pop'), + (r'\(', 'enum_type', '#pop'), + (r';', 'incomplete_type', '#pop'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'param_list': [ + (r'\s*((?:variable|signal|constant|file)\s+)?(\w+)\s*', 'param'), + (r'\s*,\s*', None), + (r'\s*:\s*', None, 'param_type'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'param_type': [ + (r'\s*((?:in|out|inout|buffer)\s+)?(\w+)\s*', 'param_type'), + (r'\s*;\s*', None, '#pop'), + (r"\s*:=\s*('.'|[^\s;)]+)", 'param_default'), + (r'\)\s*(?:return\s+(\w+)\s*)?;', 'end_subprogram', '#pop:2'), + (r'\)\s*(?:return\s+(\w+)\s*)?is', None, '#pop:2'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'simple_func': [ + (r'\s+return\s+(\w+)\s*;', 'end_subprogram', '#pop'), + (r'\s+return\s+(\w+)\s+is', None, '#pop'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'component': [ + (r'generic\s*\(', None, 'generic_list'), + (r'port\s*\(', None, 'port_list'), + (r'end\s+component\s*\w*;', 'end_component', '#pop'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'entity': [ + (r'generic\s*\(', None, 'generic_list'), + (r'port\s*\(', None, 'port_list'), + (r'end\s+\w+\s*;', 'end_entity', '#pop'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'architecture': [ + (r'end\s+\w+\s*;', 'end_arch', '#pop'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'generic_list': [ + (r'\s*(\w+)\s*', 'generic_param'), + (r'\s*,\s*', None), + (r'\s*:\s*', None, 'generic_param_type'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'generic_param_type': [ + (r'\s*(\w+)[ \t\r\f\v]*', 'generic_param_type'), + (r'\s*;\s*', None, '#pop'), + (r"\s*:=\s*([\w']+)", 'generic_param_default'), + (r'\)\s*;\s*--(.*)\n', 'line_comment', '#pop:2'), + (r'\n\s*\)\s*;\s*--(.*)\n', 'generic_list_comment', '#pop:2'), + (r'\n\s*', None), + (r'\)\s*;', 'end_generic', '#pop:2'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'port_list': [ + (r'\s*(\w+)\s*', 'port_param'), + (r'\s*,\s*', None), + (r'\s*:\s*', None, 'port_param_type'), + (r'--#\s*{{(.*)}}\n', 'section_meta'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--(.*)\n', 'line_comment'), + ], + 'port_param_type': [ + (r'\s*(in|out|inout|buffer)\s+(\w+)\s*\(', 'port_array_param_type', 'array_range'), + (r'\s*(in|out|inout|buffer)\s+(\w+)[ \t\r\f\v]*', 'port_param_type'), + (r'\s*;\s*', None, '#pop'), + (r"\s*:=\s*([\w']+)", 'port_param_default'), + (r'--(.*)\n', 'line_comment'), + (r'\)\s*;\s*--(.*)\n', 'line_comment', '#pop:2'), + (r'\n\s*\)\s*;\s*--(.*)\n', 'port_list_comment', '#pop:2'), + (r'\n\s*', None), + (r'\)\s*;', 'end_port', '#pop:2'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + ], + 'array_range': [ + (r'\(', 'open_paren', 'nested_parens'), + (r'\s*([\w\+\-\*/\s]+)(\s+(?:down)?to)\s+([\w\+\-\*/\s]+)', 'array_range_val'), + (r'\)', 'array_range_end', '#pop'), + ], + 'nested_parens': [ + (r'\(', 'open_paren', 'nested_parens'), + (r'\s*([\w\+\-\*/\s]+)(\s+(?:down)?to)\s+([\w\+\-\*/\s]+)', 'array_range_val'), + (r'\)', 'close_paren', '#pop'), + ], + 'block_comment': [ + (r'\*/', 'end_comment', '#pop'), + ], } VhdlLexer = MiniLexer(vhdl_tokens, flags=re.MULTILINE | re.IGNORECASE) class VhdlObject(object): - """Base class for parsed VHDL objects - - Args: - name (str): Name of the object - desc (str): Description from object metacomments - """ - - def __init__(self, name, desc=None): - self.name = name - self.kind = 'unknown' - self.desc = desc + '''Base class for parsed VHDL objects + Args: + name (str): Name of the object + desc (str): Description from object metacomments + ''' + def __init__(self, name, desc=None): + self.name = name + self.kind = 'unknown' + self.desc = desc class VhdlParameter(object): - """Parameter to subprograms, ports, and generics - - Args: - name (str): Name of the object - mode (str): Direction mode for the parameter - data_type (str): Type name for the parameter - default_value (str): Default value of the parameter - desc (str): Description from object metacomments - """ - - def __init__(self, name, mode=None, data_type=None, default_value=None, desc=None): - self.name = name - self.mode = mode - self.data_type = data_type - self.default_value = default_value - self.desc = desc - - def __str__(self): - if self.mode is not None: - param = '{} : {} {}'.format(self.name, self.mode, self.data_type) - else: - param = '{} : {}'.format(self.name, self.data_type) - if self.default_value is not None: - param = '{} := {}'.format(param, self.default_value) - return param - - def __repr__(self): - return "VhdlParameter('{}', '{}', '{}')".format(self.name, self.mode, self.data_type) - + '''Parameter to subprograms, ports, and generics + + Args: + name (str): Name of the object + mode (str): Direction mode for the parameter + data_type (str): Type name for the parameter + default_value (str): Default value of the parameter + desc (str): Description from object metacomments + param_desc (str): Description of the parameter + ''' + def __init__(self, name, mode=None, data_type=None, default_value=None, desc=None, param_desc = None): + self.name = name + self.mode = mode + self.data_type = data_type + self.default_value = default_value + self.desc = desc + self.param_desc = None + + def __str__(self): + if self.mode is not None: + param = '{} : {} {}'.format(self.name, self.mode, self.data_type.name + self.data_type.arange) + else: + param = '{} : {}'.format(self.name, self.data_type.name + self.data_type.arange) + if self.default_value is not None: + param = '{} := {}'.format(param, self.default_value) + if self.param_desc is not None: + param = '{} --{}'.format(param, self.param_desc) + return param + + def __repr__(self): + return "VhdlParameter('{}', '{}', '{}')".format(self.name, self.mode, self.data_type.name + self.data_type.arange) + +class VhdlParameterType(object): + '''Parameter type definition + + Args: + name (str): Name of the type + direction(str): "to" or "downto" + r_bound (str): A simple expression based on digits or variable names + l_bound (str): A simple expression based on digits or variable names + arange (str): Original array range string + ''' + def __init__(self, name, direction = "", r_bound = "", l_bound = "", arange = ""): + self.name = name + self.direction = direction.strip() + self.r_bound = r_bound.strip() + self.l_bound = l_bound.strip() + self.arange = arange + + def __repr__(self): + return "VhdlParameterType('{}','{}')".format(self.name, self.arange) class VhdlPackage(VhdlObject): - """Package declaration + '''Package declaration - Args: - name (str): Name of the package - desc (str): Description from object metacomments - """ + Args: + name (str): Name of the package + desc (str): Description from object metacomments + ''' + def __init__(self, name, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'package' - def __init__(self, name, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'package' +class VhdlType(VhdlObject): + '''Type definition + + Args: + name (str): Name of the type + package (str): Package containing the type + type_of (str): Object type of this type definition + desc (str, optional): Description from object metacomments + ''' + def __init__(self, name, package, type_of, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'type' + self.package = package + self.type_of = type_of + def __repr__(self): + return "VhdlType('{}', '{}')".format(self.name, self.type_of) -class VhdlType(VhdlObject): - """Type definition +class VhdlSubtype(VhdlObject): + '''Subtype definition + + Args: + name (str): Name of the subtype + package (str): Package containing the subtype + base_type (str): Base type name derived from + desc (str, optional): Description from object metacomments + ''' + def __init__(self, name, package, base_type, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'subtype' + self.package = package + self.base_type = base_type + def __repr__(self): + return "VhdlSubtype('{}', '{}')".format(self.name, self.base_type) - Args: - name (str): Name of the type - package (str): Package containing the type - type_of (str): Object type of this type definition - desc (str, optional): Description from object metacomments - """ - def __init__(self, name, package, type_of, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'type' - self.package = package - self.type_of = type_of +class VhdlConstant(VhdlObject): + '''Constant definition + + Args: + name (str): Name of the constant + package (str): Package containing the constant + base_type (str): Type fo the constant + desc (str, optional): Description from object metacomments + ''' + def __init__(self, name, package, base_type, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'constant' + self.package = package + self.base_type = base_type + def __repr__(self): + return "VhdlConstant('{}', '{}')".format(self.name, self.base_type) - def __repr__(self): - return "VhdlType('{}', '{}')".format(self.name, self.type_of) +class VhdlFunction(VhdlObject): + '''Function declaration + + Args: + name (str): Name of the function + package (str): Package containing the function + parameters (list of VhdlParameter): Parameters to the function + return_type (str, optional): Type of the return value + desc (str, optional): Description from object metacomments + ''' + def __init__(self, name, package, parameters, return_type=None, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'function' + self.package = package + self.parameters = parameters + self.return_type = return_type + + def __repr__(self): + return "VhdlFunction('{}')".format(self.name) -class VhdlSubtype(VhdlObject): - """Subtype definition - Args: - name (str): Name of the subtype - package (str): Package containing the subtype - base_type (str): Base type name derived from - desc (str, optional): Description from object metacomments - """ +class VhdlProcedure(VhdlObject): + '''Procedure declaration + + Args: + name (str): Name of the procedure + package (str): Package containing the procedure + parameters (list of VhdlParameter): Parameters to the procedure + desc (str, optional): Description from object metacomments + ''' + def __init__(self, name, package, parameters, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'procedure' + self.package = package + self.parameters = parameters + + def __repr__(self): + return "VhdlProcedure('{}')".format(self.name) + +class VhdlEntity(VhdlObject): + '''Entity declaration + Args: + name (str): Name of the entity + ports (list of VhdlParameter): Port parameters to the entity + generics (list of VhdlParameter): Generic parameters to the entity + sections (list of str): Metacomment sections + desc (str, optional): Description from object metacomments + ''' + def __init__(self, name, ports, generics=None, sections=None, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'entity' + self.generics = generics if generics is not None else [] + self.ports = ports + self.sections = sections if sections is not None else {} + + def __repr__(self): + return "VhdlEntity('{}')".format(self.name) + + def dump(self): + print('VHDL entity: {}'.format(self.name)) + for p in self.ports: + print('\t{} ({}), {} ({})'.format(p.name, type(p.name), p.data_type, type(p.data_type))) - def __init__(self, name, package, base_type, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'subtype' - self.package = package - self.base_type = base_type +class VhdlComponent(VhdlObject): + '''Component declaration + + Args: + name (str): Name of the component + package (str): Package containing the component + ports (list of VhdlParameter): Port parameters to the component + generics (list of VhdlParameter): Generic parameters to the component + sections (list of str): Metacomment sections + desc (str, optional): Description from object metacomments + ''' + def __init__(self, name, package, ports, generics=None, sections=None, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'component' + self.package = package + self.generics = generics if generics is not None else [] + self.ports = ports + self.sections = sections if sections is not None else {} + + def __repr__(self): + return "VhdlComponent('{}')".format(self.name) + + def dump(self): + print('VHDL component: {}'.format(self.name)) + for p in self.ports: + print('\t{} ({}), {} ({})'.format(p.name, type(p.name), p.data_type, type(p.data_type))) - def __repr__(self): - return "VhdlSubtype('{}', '{}')".format(self.name, self.base_type) +def parse_vhdl_file(fname): + '''Parse a named VHDL file -class VhdlConstant(VhdlObject): - """Constant definition + Args: + fname(str): Name of file to parse + Returns: + Parsed objects. + ''' + with open(fname, 'rt') as fh: + text = fh.read() + return parse_vhdl(text) - Args: - name (str): Name of the constant - package (str): Package containing the constant - base_type (str): Type fo the constant - desc (str, optional): Description from object metacomments - """ +def parse_vhdl(text): + '''Parse a text buffer of VHDL code + + Args: + text(str): Source code to parse + Returns: + Parsed objects. + ''' + lex = VhdlLexer + + name = None + kind = None + saved_type = None + end_param_group = False + cur_package = None + + metacomments = [] + parameters = [] + param_items = [] + + generics = [] + ports = [] + sections = [] + port_param_index = 0 + last_items = [] + array_range_start_pos = 0 + + objects = [] + + for pos, action, groups in lex.run(text): + if action == 'metacomment': + realigned = re.sub(r'^#+', lambda m: ' ' * len(m.group(0)), groups[0]) + if not last_items: + metacomments.append(realigned) + else: + for i in last_items: + i.desc = realigned + if action == 'section_meta': + sections.append((port_param_index, groups[0])) + + elif action == 'function': + kind = 'function' + name = groups[0] + param_items = [] + parameters = [] + elif action == 'procedure': + kind = 'procedure' + name = groups[0] + param_items = [] + parameters = [] + elif action == 'param': + if end_param_group: + # Complete previous parameters + for i in param_items: + parameters.append(i) + param_items = [] + end_param_group = False + + param_items.append(VhdlParameter(groups[1])) + elif action == 'param_type': + mode, ptype = groups + + if mode is not None: + mode = mode.strip() + + for i in param_items: # Set mode and type for all pending parameters + i.mode = mode + i.data_type = ptype + + end_param_group = True + + elif action == 'param_default': + for i in param_items: + i.default_value = groups[0] + + elif action == 'end_subprogram': + # Complete last parameters + for i in param_items: + parameters.append(i) + + if kind == 'function': + vobj = VhdlFunction(name, cur_package, parameters, groups[0], metacomments) + else: + vobj = VhdlProcedure(name, cur_package, parameters, metacomments) + + objects.append(vobj) + + metacomments = [] + parameters = [] + param_items = [] + kind = None + name = None + + elif action == 'entity': + kind = 'entity' + name = groups[0] + generics = [] + ports = [] + param_items = [] + sections = [] + port_param_index = 0 + + elif action == 'component': + kind = 'component' + name = groups[0] + generics = [] + ports = [] + param_items = [] + sections = [] + port_param_index = 0 + + elif action == 'generic_param': + param_items.append(groups[0]) + + elif action == 'generic_param_type': + ptype = groups[0] + last_items = [] + for i in param_items: + p = VhdlParameter(i, 'in', VhdlParameterType(ptype)) + generics.append(p) + last_items.append(p) + + param_items = [] + + elif action == 'generic_param_default': + for i in last_items: + i.default_value = groups[0] + + elif action == 'port_param': + param_items.append(groups[0]) + port_param_index += 1 + + elif action == 'port_param_type': + mode, ptype = groups + + last_items = [] + for i in param_items: + p = VhdlParameter(i, mode, VhdlParameterType(ptype)) + ports.append(p) + last_items.append(p) + + param_items = [] + + elif action == 'port_param_default': + for i in last_items: + i.default_value = groups[0] + + elif action == 'port_array_param_type': + mode, ptype = groups + array_range_start_pos = pos[1] + + elif action == 'array_range_val': + l_bound, direction, r_bound = groups + + elif action == 'array_range_end': + arange = text[array_range_start_pos:pos[0]+1] + + last_items = [] + for i in param_items: + p = VhdlParameter(i, mode, VhdlParameterType(ptype, direction, r_bound, l_bound, arange)) + ports.append(p) + last_items.append(p) + + param_items = [] + + elif action == 'end_entity': + vobj = VhdlEntity(name, ports, generics, dict(sections), metacomments) + objects.append(vobj) + last_items = [] + metacomments = [] + + elif action == 'end_component': + vobj = VhdlComponent(name, cur_package, ports, generics, dict(sections), metacomments) + objects.append(vobj) + last_items = [] + metacomments = [] + + elif action == 'package': + objects.append(VhdlPackage(groups[0])) + cur_package = groups[0] + kind = None + name = None + + elif action == 'type': + saved_type = groups[0] + + elif action in ('array_type', 'file_type', 'access_type', 'record_type', 'range_type', 'enum_type', 'incomplete_type'): + vobj = VhdlType(saved_type, cur_package, action, metacomments) + objects.append(vobj) + kind = None + name = None + metacomments = [] + + elif action == 'subtype': + vobj = VhdlSubtype(groups[0], cur_package, groups[1], metacomments) + objects.append(vobj) + kind = None + name = None + metacomments = [] + + elif action == 'constant': + vobj = VhdlConstant(groups[0], cur_package, groups[1], metacomments) + objects.append(vobj) + kind = None + name = None + metacomments = [] + + elif action == 'line_comment': + for i in last_items: + if not i.param_desc: + i.param_desc = groups[0] + + return objects - def __init__(self, name, package, base_type, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'constant' - self.package = package - self.base_type = base_type - def __repr__(self): - return "VhdlConstant('{}', '{}')".format(self.name, self.base_type) +def subprogram_prototype(vo): + '''Generate a canonical prototype string + Args: + vo (VhdlFunction, VhdlProcedure): Subprogram object + Returns: + Prototype string. + ''' -class VhdlFunction(VhdlObject): - """Function declaration + plist = '; '.join(str(p) for p in vo.parameters) - Args: - name (str): Name of the function - package (str): Package containing the function - parameters (list of VhdlParameter): Parameters to the function - return_type (str, optional): Type of the return value - desc (str, optional): Description from object metacomments - """ + if isinstance(vo, VhdlFunction): + if len(vo.parameters) > 0: + proto = 'function {}({}) return {};'.format(vo.name, plist, vo.return_type) + else: + proto = 'function {} return {};'.format(vo.name, vo.return_type) - def __init__(self, name, package, parameters, return_type=None, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'function' - self.package = package - self.parameters = parameters - self.return_type = return_type + else: # procedure + proto = 'procedure {}({});'.format(vo.name, plist) - def __repr__(self): - return "VhdlFunction('{}')".format(self.name) + return proto +def subprogram_signature(vo, fullname=None): + '''Generate a signature string -class VhdlProcedure(VhdlObject): - """Procedure declaration + Args: + vo (VhdlFunction, VhdlProcedure): Subprogram object + Returns: + Signature string. + ''' - Args: - name (str): Name of the procedure - package (str): Package containing the procedure - parameters (list of VhdlParameter): Parameters to the procedure - desc (str, optional): Description from object metacomments - """ + if fullname is None: + fullname = vo.name - def __init__(self, name, package, parameters, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'procedure' - self.package = package - self.parameters = parameters + if isinstance(vo, VhdlFunction): + plist = ','.join(p.data_type for p in vo.parameters) + sig = '{}[{} return {}]'.format(fullname, plist, vo.return_type) + else: # procedure + plist = ','.join(p.data_type for p in vo.parameters) + sig = '{}[{}]'.format(fullname, plist) - def __repr__(self): - return "VhdlProcedure('{}')".format(self.name) + return sig -class VhdlComponent(VhdlObject): - """Component declaration +def is_vhdl(fname): + '''Identify file as VHDL by its extension - Args: - name (str): Name of the component - package (str): Package containing the component - ports (list of VhdlParameter): Port parameters to the component - generics (list of VhdlParameter): Generic parameters to the component - sections (list of str): Metacomment sections - desc (str, optional): Description from object metacomments - """ - - def __init__(self, name, package, ports, generics=None, sections=None, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'component' - self.package = package - self.generics = generics if generics is not None else [] - self.ports = ports - self.sections = sections if sections is not None else {} - - def __repr__(self): - return "VhdlComponent('{}')".format(self.name) - - def dump(self): - print('VHDL component: {}'.format(self.name)) - for p in self.ports: - print('\t{} ({}), {} ({})'.format(p.name, type(p.name), p.data_type, type(p.data_type))) + Args: + fname (str): File name to check + Returns: + True when file has a VHDL extension. + ''' + return os.path.splitext(fname)[1].lower() in ('.vhdl', '.vhd') -def parse_vhdl_file(fname): - """Parse a named VHDL file +class VhdlExtractor(object): + '''Utility class that caches parsed objects and tracks array type definitions - Args: - fname(str): Name of file to parse - Returns: - Parsed objects. - """ - with open(fname, 'rt') as fh: - text = fh.read() - return parse_vhdl(text) + Args: + array_types(set): Initial array types + ''' + def __init__(self, array_types=set()): + self.array_types = set(('std_ulogic_vector', 'std_logic_vector', + 'signed', 'unsigned', 'bit_vector')) + self.array_types |= array_types + self.object_cache = {} -def parse_vhdl(text): - """Parse a text buffer of VHDL code + def extract_objects(self, fname, type_filter=None): + '''Extract objects from a source file Args: - text(str): Source code to parse + fname (str): File to parse + type_filter (class, optional): Object class to filter results Returns: - Parsed objects. - """ - lex = VhdlLexer - - name = None - kind = None - saved_type = None - end_param_group = False - cur_package = None - - metacomments = [] - parameters = [] - param_items = [] - - generics = [] - ports = [] - sections = [] - port_param_index = 0 - last_item = None - array_range_start_pos = 0 - + List of parsed objects. + ''' objects = [] + if fname in self.object_cache: + objects = self.object_cache[fname] + else: + with io.open(fname, 'rt', encoding='latin-1') as fh: + text = fh.read() + objects = parse_vhdl(text) + self.object_cache[fname] = objects + self._register_array_types(objects) - for pos, action, groups in lex.run(text): - if action == 'metacomment': - realigned = re.sub(r'^#+', lambda m: ' ' * len(m.group(0)), groups[0]) - if last_item is None: - metacomments.append(realigned) - else: - last_item.desc = realigned - if action == 'section_meta': - sections.append((port_param_index, groups[0])) - - elif action == 'function': - kind = 'function' - name = groups[0] - param_items = [] - parameters = [] - elif action == 'procedure': - kind = 'procedure' - name = groups[0] - param_items = [] - parameters = [] - elif action == 'param': - if end_param_group: - # Complete previous parameters - for i in param_items: - parameters.append(i) - param_items = [] - end_param_group = False - - param_items.append(VhdlParameter(groups[1])) - elif action == 'param_type': - mode, ptype = groups - - if mode is not None: - mode = mode.strip() - - for i in param_items: # Set mode and type for all pending parameters - i.mode = mode - i.data_type = ptype - - end_param_group = True - - elif action == 'param_default': - for i in param_items: - i.default_value = groups[0] - - elif action == 'end_subprogram': - # Complete last parameters - for i in param_items: - parameters.append(i) - - if kind == 'function': - vobj = VhdlFunction(name, cur_package, parameters, groups[0], metacomments) - else: - vobj = VhdlProcedure(name, cur_package, parameters, metacomments) - - objects.append(vobj) - - metacomments = [] - parameters = [] - param_items = [] - kind = None - name = None - - elif action == 'component': - kind = 'component' - name = groups[0] - generics = [] - ports = [] - param_items = [] - sections = [] - port_param_index = 0 - - elif action == 'generic_param': - param_items.append(groups[0]) - - elif action == 'generic_param_type': - ptype = groups[0] - - for i in param_items: - generics.append(VhdlParameter(i, 'in', ptype)) - param_items = [] - last_item = generics[-1] - - elif action == 'port_param': - param_items.append(groups[0]) - port_param_index += 1 - - elif action == 'port_param_type': - mode, ptype = groups - - for i in param_items: - ports.append(VhdlParameter(i, mode, ptype)) - - param_items = [] - last_item = ports[-1] - - elif action == 'port_array_param_type': - mode, ptype = groups - array_range_start_pos = pos[1] - - elif action == 'array_range_end': - arange = text[array_range_start_pos:pos[0] + 1] - - for i in param_items: - ports.append(VhdlParameter(i, mode, ptype + arange)) - - param_items = [] - last_item = ports[-1] - - elif action == 'end_component': - vobj = VhdlComponent(name, cur_package, ports, generics, dict(sections), metacomments) - objects.append(vobj) - last_item = None - metacomments = [] - - elif action == 'package': - objects.append(VhdlPackage(groups[0])) - cur_package = groups[0] - kind = None - name = None - - elif action == 'type': - saved_type = groups[0] - - elif action in ( - 'array_type', 'file_type', 'access_type', 'record_type', 'range_type', 'enum_type', 'incomplete_type'): - vobj = VhdlType(saved_type, cur_package, action, metacomments) - objects.append(vobj) - kind = None - name = None - metacomments = [] - - elif action == 'subtype': - vobj = VhdlSubtype(groups[0], cur_package, groups[1], metacomments) - objects.append(vobj) - kind = None - name = None - metacomments = [] - - elif action == 'constant': - vobj = VhdlConstant(groups[0], cur_package, groups[1], metacomments) - objects.append(vobj) - kind = None - name = None - metacomments = [] + if type_filter: + objects = [o for o in objects if isinstance(o, type_filter)] return objects - -def subprogram_prototype(vo): - """Generate a canonical prototype string + def extract_objects_from_source(self, text, type_filter=None): + '''Extract object declarations from a text buffer Args: - vo (VhdlFunction, VhdlProcedure): Subprogram object + text (str): Source code to parse + type_filter (class, optional): Object class to filter results Returns: - Prototype string. - """ + List of parsed objects. + ''' + objects = parse_vhdl(text) + self._register_array_types(objects) - plist = '; '.join(str(p) for p in vo.parameters) + if type_filter: + objects = [o for o in objects if isinstance(o, type_filter)] - if isinstance(vo, VhdlFunction): - if len(vo.parameters) > 0: - proto = 'function {}({}) return {};'.format(vo.name, plist, vo.return_type) - else: - proto = 'function {} return {};'.format(vo.name, vo.return_type) - - else: # procedure - proto = 'procedure {}({});'.format(vo.name, plist) - - return proto + return objects -def subprogram_signature(vo, fullname=None): - """Generate a signature string + def is_array(self, data_type): + '''Check if a type is a known array type Args: - vo (VhdlFunction, VhdlProcedure): Subprogram object + data_type (str): Name of type to check Returns: - Signature string. - """ + True if ``data_type`` is a known array type. + ''' - if fullname is None: - fullname = vo.name + # Split off any brackets + data_type = data_type.split('[')[0].strip() - if isinstance(vo, VhdlFunction): - plist = ','.join(p.data_type for p in vo.parameters) - sig = '{}[{} return {}]'.format(fullname, plist, vo.return_type) - else: # procedure - plist = ','.join(p.data_type for p in vo.parameters) - sig = '{}[{}]'.format(fullname, plist) + return data_type.lower() in self.array_types - return sig - -def is_vhdl(fname): - """Identify file as VHDL by its extension + def _add_array_types(self, type_defs): + '''Add array data types to internal registry Args: - fname (str): File name to check - Returns: - True when file has a VHDL extension. - """ - return os.path.splitext(fname)[1].lower() in ('.vhdl', '.vhd') - + type_defs (dict): Dictionary of type definitions + ''' + if 'arrays' in type_defs: + self.array_types |= set(type_defs['arrays']) -class VhdlExtractor(object): - """Utility class that caches parsed objects and tracks array type definitions + def load_array_types(self, fname): + '''Load file of previously extracted data types Args: - array_types(set): Initial array types - """ - - def __init__(self, array_types=set()): - self.array_types = {'std_ulogic_vector', 'std_logic_vector', 'signed', 'unsigned', 'bit_vector'} - - self.array_types |= array_types - self.object_cache = {} - - def extract_objects(self, fname, type_filter=None): - """Extract objects from a source file - - Args: - fname (str): File to parse - type_filter (class, optional): Object class to filter results - Returns: - List of parsed objects. - """ - objects = [] - if fname in self.object_cache: - objects = self.object_cache[fname] - else: - with io.open(fname, 'rt', encoding='latin-1') as fh: - text = fh.read() - objects = parse_vhdl(text) - self.object_cache[fname] = objects - self._register_array_types(objects) - - if type_filter: - objects = [o for o in objects if isinstance(o, type_filter)] - - return objects - - def extract_objects_from_source(self, text, type_filter=None): - """Extract object declarations from a text buffer - - Args: - text (str): Source code to parse - type_filter (class, optional): Object class to filter results - Returns: - List of parsed objects. - """ - objects = parse_vhdl(text) - self._register_array_types(objects) - - if type_filter: - objects = [o for o in objects if isinstance(o, type_filter)] - - return objects - - def is_array(self, data_type): - """Check if a type is a known array type - - Args: - data_type (str): Name of type to check - Returns: - True if ``data_type`` is a known array type. - """ - - # Split off any brackets - data_type = data_type.split('[')[0].strip() - - return data_type.lower() in self.array_types - - def _add_array_types(self, type_defs): - """Add array data types to internal registry - - Args: - type_defs (dict): Dictionary of type definitions - """ - if 'arrays' in type_defs: - self.array_types |= set(type_defs['arrays']) - - def load_array_types(self, fname): - """Load file of previously extracted data types - - Args: - fname (str): Name of file to load array database from - """ - type_defs = '' - with open(fname, 'rt') as fh: - type_defs = fh.read() + fname (str): Name of file to load array database from + ''' + type_defs = '' + with open(fname, 'rt') as fh: + type_defs = fh.read() - try: - type_defs = ast.literal_eval(type_defs) - except SyntaxError: - type_defs = {} + try: + type_defs = ast.literal_eval(type_defs) + except SyntaxError: + type_defs = {} - self._add_array_types(type_defs) + self._add_array_types(type_defs) - def save_array_types(self, fname): - """Save array type registry to a file + def save_array_types(self, fname): + '''Save array type registry to a file - Args: - fname (str): Name of file to save array database to - """ - type_defs = {'arrays': sorted(list(self.array_types))} - with open(fname, 'wt') as fh: - pprint(type_defs, stream=fh) + Args: + fname (str): Name of file to save array database to + ''' + type_defs = {'arrays': sorted(list(self.array_types))} + with open(fname, 'wt') as fh: + pprint(type_defs, stream=fh) - def _register_array_types(self, objects): - """Add array type definitions to internal registry + def _register_array_types(self, objects): + '''Add array type definitions to internal registry - Args: - objects (list of VhdlType or VhdlSubtype): Array types to track - """ - # Add all array types directly - types = [o for o in objects if isinstance(o, VhdlType) and o.type_of == 'array_type'] - for t in types: - self.array_types.add(t.name) + Args: + objects (list of VhdlType or VhdlSubtype): Array types to track + ''' + # Add all array types directly + types = [o for o in objects if isinstance(o, VhdlType) and o.type_of == 'array_type'] + for t in types: + self.array_types.add(t.name) - subtypes = {o.name: o.base_type for o in objects if isinstance(o, VhdlSubtype)} + subtypes = {o.name:o.base_type for o in objects if isinstance(o, VhdlSubtype)} - # Find all subtypes of an array type - for k, v in subtypes.items(): - while v in subtypes: # Follow subtypes of subtypes - v = subtypes[v] - if v in self.array_types: - self.array_types.add(k) + # Find all subtypes of an array type + for k,v in subtypes.items(): + while v in subtypes: # Follow subtypes of subtypes + v = subtypes[v] + if v in self.array_types: + self.array_types.add(k) - def register_array_types_from_sources(self, source_files): - """Add array type definitions from a file list to internal registry + def register_array_types_from_sources(self, source_files): + '''Add array type definitions from a file list to internal registry - Args: - source_files (list of str): Files to parse for array definitions - """ - for fname in source_files: - if is_vhdl(fname): - self._register_array_types(self.extract_objects(fname)) + Args: + source_files (list of str): Files to parse for array definitions + ''' + for fname in source_files: + if is_vhdl(fname): + self._register_array_types(self.extract_objects(fname)) if __name__ == '__main__': - ve = VhdlExtractor() - code = """ + ve = VhdlExtractor() + code = ''' package foo is function afunc(q,w,e : std_ulogic; h,j,k : unsigned) return std_ulogic; @@ -728,26 +806,28 @@ def register_array_types_from_sources(self, source_files): component acomp is port ( - a,b,c : in std_ulogic; - f,g,h : inout bit - ); + a,b,c : in std_ulogic; -- no default value + f,g,h : inout bit := '1'; -- bit ports + v : in std_logic_vector(lBound -1 downto 0) -- array range + ); -- port list comment + end component; end package; - """ - - objs = ve.extract_objects_from_source(code) - - for o in objs: - print(o.name) - try: - for p in o.parameters: - print(p) - except: - pass - - try: - for p in o.ports: - print(p) - except: - pass + ''' + + objs = ve.extract_objects_from_source(code) + + for o in objs: + print(o.name) + try: + for p in o.parameters: + print(p) + except: + pass + + try: + for p in o.ports: + print(p) + except: + pass From c2fcf2bb0e677f86f9f1084433b2c358a5b7d1c8 Mon Sep 17 00:00:00 2001 From: michael-etzkorn Date: Thu, 18 Nov 2021 09:27:12 -0600 Subject: [PATCH 2/6] Andres Manelli hotfix for type parsing in architectures --- hdlparse/vhdl_parser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hdlparse/vhdl_parser.py b/hdlparse/vhdl_parser.py index af9789d..05e424c 100644 --- a/hdlparse/vhdl_parser.py +++ b/hdlparse/vhdl_parser.py @@ -94,6 +94,7 @@ 'architecture': [ (r'end\s+\w+\s*;', 'end_arch', '#pop'), (r'/\*', 'block_comment', 'block_comment'), + (r'type\s+(\w+)\s*is', 'type', 'type_decl'), (r'--.*\n', None), ], 'generic_list': [ From 32c87227e32cc9fde10e5604260a0a61696cdc45 Mon Sep 17 00:00:00 2001 From: michael-etzkorn Date: Sun, 28 Nov 2021 09:35:22 -0600 Subject: [PATCH 3/6] Replaced single quote docstrings with double quotes --- hdlparse/vhdl_parser.py | 102 ++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/hdlparse/vhdl_parser.py b/hdlparse/vhdl_parser.py index 05e424c..179c157 100644 --- a/hdlparse/vhdl_parser.py +++ b/hdlparse/vhdl_parser.py @@ -158,19 +158,19 @@ class VhdlObject(object): - '''Base class for parsed VHDL objects + """Base class for parsed VHDL objects Args: name (str): Name of the object desc (str): Description from object metacomments - ''' + """ def __init__(self, name, desc=None): self.name = name self.kind = 'unknown' self.desc = desc class VhdlParameter(object): - '''Parameter to subprograms, ports, and generics + """Parameter to subprograms, ports, and generics Args: name (str): Name of the object @@ -179,7 +179,7 @@ class VhdlParameter(object): default_value (str): Default value of the parameter desc (str): Description from object metacomments param_desc (str): Description of the parameter - ''' + """ def __init__(self, name, mode=None, data_type=None, default_value=None, desc=None, param_desc = None): self.name = name self.mode = mode @@ -203,15 +203,15 @@ def __repr__(self): return "VhdlParameter('{}', '{}', '{}')".format(self.name, self.mode, self.data_type.name + self.data_type.arange) class VhdlParameterType(object): - '''Parameter type definition + """Parameter type definition - Args: + Args: name (str): Name of the type direction(str): "to" or "downto" r_bound (str): A simple expression based on digits or variable names l_bound (str): A simple expression based on digits or variable names arange (str): Original array range string - ''' + """ def __init__(self, name, direction = "", r_bound = "", l_bound = "", arange = ""): self.name = name self.direction = direction.strip() @@ -223,25 +223,25 @@ def __repr__(self): return "VhdlParameterType('{}','{}')".format(self.name, self.arange) class VhdlPackage(VhdlObject): - '''Package declaration + """Package declaration Args: name (str): Name of the package desc (str): Description from object metacomments - ''' + """ def __init__(self, name, desc=None): VhdlObject.__init__(self, name, desc) self.kind = 'package' class VhdlType(VhdlObject): - '''Type definition + """Type definition Args: name (str): Name of the type package (str): Package containing the type type_of (str): Object type of this type definition desc (str, optional): Description from object metacomments - ''' + """ def __init__(self, name, package, type_of, desc=None): VhdlObject.__init__(self, name, desc) self.kind = 'type' @@ -252,14 +252,14 @@ def __repr__(self): class VhdlSubtype(VhdlObject): - '''Subtype definition + """Subtype definition Args: name (str): Name of the subtype package (str): Package containing the subtype base_type (str): Base type name derived from desc (str, optional): Description from object metacomments - ''' + """ def __init__(self, name, package, base_type, desc=None): VhdlObject.__init__(self, name, desc) self.kind = 'subtype' @@ -270,14 +270,14 @@ def __repr__(self): class VhdlConstant(VhdlObject): - '''Constant definition + """Constant definition Args: name (str): Name of the constant package (str): Package containing the constant base_type (str): Type fo the constant desc (str, optional): Description from object metacomments - ''' + """ def __init__(self, name, package, base_type, desc=None): VhdlObject.__init__(self, name, desc) self.kind = 'constant' @@ -288,7 +288,7 @@ def __repr__(self): class VhdlFunction(VhdlObject): - '''Function declaration + """Function declaration Args: name (str): Name of the function @@ -296,7 +296,7 @@ class VhdlFunction(VhdlObject): parameters (list of VhdlParameter): Parameters to the function return_type (str, optional): Type of the return value desc (str, optional): Description from object metacomments - ''' + """ def __init__(self, name, package, parameters, return_type=None, desc=None): VhdlObject.__init__(self, name, desc) self.kind = 'function' @@ -309,14 +309,14 @@ def __repr__(self): class VhdlProcedure(VhdlObject): - '''Procedure declaration + """Procedure declaration Args: name (str): Name of the procedure package (str): Package containing the procedure parameters (list of VhdlParameter): Parameters to the procedure desc (str, optional): Description from object metacomments - ''' + """ def __init__(self, name, package, parameters, desc=None): VhdlObject.__init__(self, name, desc) self.kind = 'procedure' @@ -327,14 +327,14 @@ def __repr__(self): return "VhdlProcedure('{}')".format(self.name) class VhdlEntity(VhdlObject): - '''Entity declaration + """Entity declaration Args: name (str): Name of the entity ports (list of VhdlParameter): Port parameters to the entity generics (list of VhdlParameter): Generic parameters to the entity sections (list of str): Metacomment sections desc (str, optional): Description from object metacomments - ''' + """ def __init__(self, name, ports, generics=None, sections=None, desc=None): VhdlObject.__init__(self, name, desc) self.kind = 'entity' @@ -351,7 +351,7 @@ def dump(self): print('\t{} ({}), {} ({})'.format(p.name, type(p.name), p.data_type, type(p.data_type))) class VhdlComponent(VhdlObject): - '''Component declaration + """Component declaration Args: name (str): Name of the component @@ -360,7 +360,7 @@ class VhdlComponent(VhdlObject): generics (list of VhdlParameter): Generic parameters to the component sections (list of str): Metacomment sections desc (str, optional): Description from object metacomments - ''' + """ def __init__(self, name, package, ports, generics=None, sections=None, desc=None): VhdlObject.__init__(self, name, desc) self.kind = 'component' @@ -379,25 +379,25 @@ def dump(self): def parse_vhdl_file(fname): - '''Parse a named VHDL file + """Parse a named VHDL file Args: fname(str): Name of file to parse Returns: Parsed objects. - ''' + """ with open(fname, 'rt') as fh: text = fh.read() return parse_vhdl(text) def parse_vhdl(text): - '''Parse a text buffer of VHDL code + """Parse a text buffer of VHDL code Args: text(str): Source code to parse Returns: Parsed objects. - ''' + """ lex = VhdlLexer name = None @@ -606,13 +606,13 @@ def parse_vhdl(text): def subprogram_prototype(vo): - '''Generate a canonical prototype string + """Generate a canonical prototype string Args: vo (VhdlFunction, VhdlProcedure): Subprogram object Returns: Prototype string. - ''' + """ plist = '; '.join(str(p) for p in vo.parameters) @@ -628,13 +628,13 @@ def subprogram_prototype(vo): return proto def subprogram_signature(vo, fullname=None): - '''Generate a signature string + """Generate a signature string Args: vo (VhdlFunction, VhdlProcedure): Subprogram object Returns: Signature string. - ''' + """ if fullname is None: fullname = vo.name @@ -650,22 +650,22 @@ def subprogram_signature(vo, fullname=None): def is_vhdl(fname): - '''Identify file as VHDL by its extension + """Identify file as VHDL by its extension Args: fname (str): File name to check Returns: True when file has a VHDL extension. - ''' + """ return os.path.splitext(fname)[1].lower() in ('.vhdl', '.vhd') class VhdlExtractor(object): - '''Utility class that caches parsed objects and tracks array type definitions + """Utility class that caches parsed objects and tracks array type definitions Args: array_types(set): Initial array types - ''' + """ def __init__(self, array_types=set()): self.array_types = set(('std_ulogic_vector', 'std_logic_vector', 'signed', 'unsigned', 'bit_vector')) @@ -674,14 +674,14 @@ def __init__(self, array_types=set()): self.object_cache = {} def extract_objects(self, fname, type_filter=None): - '''Extract objects from a source file + """Extract objects from a source file Args: fname (str): File to parse type_filter (class, optional): Object class to filter results Returns: List of parsed objects. - ''' + """ objects = [] if fname in self.object_cache: objects = self.object_cache[fname] @@ -698,14 +698,14 @@ def extract_objects(self, fname, type_filter=None): return objects def extract_objects_from_source(self, text, type_filter=None): - '''Extract object declarations from a text buffer + """Extract object declarations from a text buffer Args: text (str): Source code to parse type_filter (class, optional): Object class to filter results Returns: List of parsed objects. - ''' + """ objects = parse_vhdl(text) self._register_array_types(objects) @@ -716,13 +716,13 @@ def extract_objects_from_source(self, text, type_filter=None): def is_array(self, data_type): - '''Check if a type is a known array type + """Check if a type is a known array type Args: data_type (str): Name of type to check Returns: True if ``data_type`` is a known array type. - ''' + """ # Split off any brackets data_type = data_type.split('[')[0].strip() @@ -731,20 +731,20 @@ def is_array(self, data_type): def _add_array_types(self, type_defs): - '''Add array data types to internal registry + """Add array data types to internal registry Args: type_defs (dict): Dictionary of type definitions - ''' + """ if 'arrays' in type_defs: self.array_types |= set(type_defs['arrays']) def load_array_types(self, fname): - '''Load file of previously extracted data types + """Load file of previously extracted data types Args: fname (str): Name of file to load array database from - ''' + """ type_defs = '' with open(fname, 'rt') as fh: type_defs = fh.read() @@ -757,21 +757,21 @@ def load_array_types(self, fname): self._add_array_types(type_defs) def save_array_types(self, fname): - '''Save array type registry to a file + """Save array type registry to a file Args: fname (str): Name of file to save array database to - ''' + """ type_defs = {'arrays': sorted(list(self.array_types))} with open(fname, 'wt') as fh: pprint(type_defs, stream=fh) def _register_array_types(self, objects): - '''Add array type definitions to internal registry + """Add array type definitions to internal registry Args: objects (list of VhdlType or VhdlSubtype): Array types to track - ''' + """ # Add all array types directly types = [o for o in objects if isinstance(o, VhdlType) and o.type_of == 'array_type'] for t in types: @@ -787,11 +787,11 @@ def _register_array_types(self, objects): self.array_types.add(k) def register_array_types_from_sources(self, source_files): - '''Add array type definitions from a file list to internal registry + """Add array type definitions from a file list to internal registry Args: source_files (list of str): Files to parse for array definitions - ''' + """ for fname in source_files: if is_vhdl(fname): self._register_array_types(self.extract_objects(fname)) From 06c8b2981ddab53dfa4a874d16feb1e83bb9e142 Mon Sep 17 00:00:00 2001 From: michael-etzkorn Date: Sun, 28 Nov 2021 09:41:39 -0600 Subject: [PATCH 4/6] Reformatted code with PyCharm --- hdlparse/vhdl_parser.py | 1439 ++++++++++++++++++++------------------- 1 file changed, 731 insertions(+), 708 deletions(-) diff --git a/hdlparse/vhdl_parser.py b/hdlparse/vhdl_parser.py index 179c157..e363b67 100644 --- a/hdlparse/vhdl_parser.py +++ b/hdlparse/vhdl_parser.py @@ -11,795 +11,818 @@ '''VHDL documentation parser''' vhdl_tokens = { - 'root': [ - (r'package\s+(\w+)\s+is', 'package', 'package'), - (r'package\s+body\s+(\w+)\s+is', 'package_body', 'package_body'), - (r'function\s+(\w+|"[^"]+")\s*\(', 'function', 'param_list'), - (r'procedure\s+(\w+)\s*\(', 'procedure', 'param_list'), - (r'function\s+(\w+)', 'function', 'simple_func'), - (r'component\s+(\w+)\s*is', 'component', 'component'), - (r'entity\s+(\w+)\s*is', 'entity', 'entity'), - (r'architecture\s+(\w+)\s*of', 'architecture', 'architecture'), - (r'subtype\s+(\w+)\s+is\s+(\w+)', 'subtype'), - (r'type\s+(\w+)\s*is', 'type', 'type_decl'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'package': [ - (r'function\s+(\w+|"[^"]+")\s*\(', 'function', 'param_list'), - (r'procedure\s+(\w+)\s*\(', 'procedure', 'param_list'), - (r'function\s+(\w+)', 'function', 'simple_func'), - (r'component\s+(\w+)\s*is', 'component', 'component'), - (r'subtype\s+(\w+)\s+is\s+(\w+)', 'subtype'), - (r'constant\s+(\w+)\s+:\s+(\w+)', 'constant'), - (r'type\s+(\w+)\s*is', 'type', 'type_decl'), - (r'end\s+\w+\s*;', None, '#pop'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'package_body': [ - (r'end\s+\w+\s*;', None, '#pop'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'type_decl': [ - (r'array', 'array_type', '#pop'), - (r'file', 'file_type', '#pop'), - (r'access', 'access_type', '#pop'), - (r'record', 'record_type', '#pop'), - (r'range', 'range_type', '#pop'), - (r'\(', 'enum_type', '#pop'), - (r';', 'incomplete_type', '#pop'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'param_list': [ - (r'\s*((?:variable|signal|constant|file)\s+)?(\w+)\s*', 'param'), - (r'\s*,\s*', None), - (r'\s*:\s*', None, 'param_type'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'param_type': [ - (r'\s*((?:in|out|inout|buffer)\s+)?(\w+)\s*', 'param_type'), - (r'\s*;\s*', None, '#pop'), - (r"\s*:=\s*('.'|[^\s;)]+)", 'param_default'), - (r'\)\s*(?:return\s+(\w+)\s*)?;', 'end_subprogram', '#pop:2'), - (r'\)\s*(?:return\s+(\w+)\s*)?is', None, '#pop:2'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'simple_func': [ - (r'\s+return\s+(\w+)\s*;', 'end_subprogram', '#pop'), - (r'\s+return\s+(\w+)\s+is', None, '#pop'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'component': [ - (r'generic\s*\(', None, 'generic_list'), - (r'port\s*\(', None, 'port_list'), - (r'end\s+component\s*\w*;', 'end_component', '#pop'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'entity': [ - (r'generic\s*\(', None, 'generic_list'), - (r'port\s*\(', None, 'port_list'), - (r'end\s+\w+\s*;', 'end_entity', '#pop'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'architecture': [ - (r'end\s+\w+\s*;', 'end_arch', '#pop'), - (r'/\*', 'block_comment', 'block_comment'), - (r'type\s+(\w+)\s*is', 'type', 'type_decl'), - (r'--.*\n', None), - ], - 'generic_list': [ - (r'\s*(\w+)\s*', 'generic_param'), - (r'\s*,\s*', None), - (r'\s*:\s*', None, 'generic_param_type'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'generic_param_type': [ - (r'\s*(\w+)[ \t\r\f\v]*', 'generic_param_type'), - (r'\s*;\s*', None, '#pop'), - (r"\s*:=\s*([\w']+)", 'generic_param_default'), - (r'\)\s*;\s*--(.*)\n', 'line_comment', '#pop:2'), - (r'\n\s*\)\s*;\s*--(.*)\n', 'generic_list_comment', '#pop:2'), - (r'\n\s*', None), - (r'\)\s*;', 'end_generic', '#pop:2'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--.*\n', None), - ], - 'port_list': [ - (r'\s*(\w+)\s*', 'port_param'), - (r'\s*,\s*', None), - (r'\s*:\s*', None, 'port_param_type'), - (r'--#\s*{{(.*)}}\n', 'section_meta'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - (r'--(.*)\n', 'line_comment'), - ], - 'port_param_type': [ - (r'\s*(in|out|inout|buffer)\s+(\w+)\s*\(', 'port_array_param_type', 'array_range'), - (r'\s*(in|out|inout|buffer)\s+(\w+)[ \t\r\f\v]*', 'port_param_type'), - (r'\s*;\s*', None, '#pop'), - (r"\s*:=\s*([\w']+)", 'port_param_default'), - (r'--(.*)\n', 'line_comment'), - (r'\)\s*;\s*--(.*)\n', 'line_comment', '#pop:2'), - (r'\n\s*\)\s*;\s*--(.*)\n', 'port_list_comment', '#pop:2'), - (r'\n\s*', None), - (r'\)\s*;', 'end_port', '#pop:2'), - (r'--#(.*)\n', 'metacomment'), - (r'/\*', 'block_comment', 'block_comment'), - ], - 'array_range': [ - (r'\(', 'open_paren', 'nested_parens'), - (r'\s*([\w\+\-\*/\s]+)(\s+(?:down)?to)\s+([\w\+\-\*/\s]+)', 'array_range_val'), - (r'\)', 'array_range_end', '#pop'), - ], - 'nested_parens': [ - (r'\(', 'open_paren', 'nested_parens'), - (r'\s*([\w\+\-\*/\s]+)(\s+(?:down)?to)\s+([\w\+\-\*/\s]+)', 'array_range_val'), - (r'\)', 'close_paren', '#pop'), - ], - 'block_comment': [ - (r'\*/', 'end_comment', '#pop'), - ], + 'root': [ + (r'package\s+(\w+)\s+is', 'package', 'package'), + (r'package\s+body\s+(\w+)\s+is', 'package_body', 'package_body'), + (r'function\s+(\w+|"[^"]+")\s*\(', 'function', 'param_list'), + (r'procedure\s+(\w+)\s*\(', 'procedure', 'param_list'), + (r'function\s+(\w+)', 'function', 'simple_func'), + (r'component\s+(\w+)\s*is', 'component', 'component'), + (r'entity\s+(\w+)\s*is', 'entity', 'entity'), + (r'architecture\s+(\w+)\s*of', 'architecture', 'architecture'), + (r'subtype\s+(\w+)\s+is\s+(\w+)', 'subtype'), + (r'type\s+(\w+)\s*is', 'type', 'type_decl'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'package': [ + (r'function\s+(\w+|"[^"]+")\s*\(', 'function', 'param_list'), + (r'procedure\s+(\w+)\s*\(', 'procedure', 'param_list'), + (r'function\s+(\w+)', 'function', 'simple_func'), + (r'component\s+(\w+)\s*is', 'component', 'component'), + (r'subtype\s+(\w+)\s+is\s+(\w+)', 'subtype'), + (r'constant\s+(\w+)\s+:\s+(\w+)', 'constant'), + (r'type\s+(\w+)\s*is', 'type', 'type_decl'), + (r'end\s+\w+\s*;', None, '#pop'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'package_body': [ + (r'end\s+\w+\s*;', None, '#pop'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'type_decl': [ + (r'array', 'array_type', '#pop'), + (r'file', 'file_type', '#pop'), + (r'access', 'access_type', '#pop'), + (r'record', 'record_type', '#pop'), + (r'range', 'range_type', '#pop'), + (r'\(', 'enum_type', '#pop'), + (r';', 'incomplete_type', '#pop'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'param_list': [ + (r'\s*((?:variable|signal|constant|file)\s+)?(\w+)\s*', 'param'), + (r'\s*,\s*', None), + (r'\s*:\s*', None, 'param_type'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'param_type': [ + (r'\s*((?:in|out|inout|buffer)\s+)?(\w+)\s*', 'param_type'), + (r'\s*;\s*', None, '#pop'), + (r"\s*:=\s*('.'|[^\s;)]+)", 'param_default'), + (r'\)\s*(?:return\s+(\w+)\s*)?;', 'end_subprogram', '#pop:2'), + (r'\)\s*(?:return\s+(\w+)\s*)?is', None, '#pop:2'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'simple_func': [ + (r'\s+return\s+(\w+)\s*;', 'end_subprogram', '#pop'), + (r'\s+return\s+(\w+)\s+is', None, '#pop'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'component': [ + (r'generic\s*\(', None, 'generic_list'), + (r'port\s*\(', None, 'port_list'), + (r'end\s+component\s*\w*;', 'end_component', '#pop'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'entity': [ + (r'generic\s*\(', None, 'generic_list'), + (r'port\s*\(', None, 'port_list'), + (r'end\s+\w+\s*;', 'end_entity', '#pop'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'architecture': [ + (r'end\s+\w+\s*;', 'end_arch', '#pop'), + (r'/\*', 'block_comment', 'block_comment'), + (r'type\s+(\w+)\s*is', 'type', 'type_decl'), + (r'--.*\n', None), + ], + 'generic_list': [ + (r'\s*(\w+)\s*', 'generic_param'), + (r'\s*,\s*', None), + (r'\s*:\s*', None, 'generic_param_type'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'generic_param_type': [ + (r'\s*(\w+)[ \t\r\f\v]*', 'generic_param_type'), + (r'\s*;\s*', None, '#pop'), + (r"\s*:=\s*([\w']+)", 'generic_param_default'), + (r'\)\s*;\s*--(.*)\n', 'line_comment', '#pop:2'), + (r'\n\s*\)\s*;\s*--(.*)\n', 'generic_list_comment', '#pop:2'), + (r'\n\s*', None), + (r'\)\s*;', 'end_generic', '#pop:2'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--.*\n', None), + ], + 'port_list': [ + (r'\s*(\w+)\s*', 'port_param'), + (r'\s*,\s*', None), + (r'\s*:\s*', None, 'port_param_type'), + (r'--#\s*{{(.*)}}\n', 'section_meta'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + (r'--(.*)\n', 'line_comment'), + ], + 'port_param_type': [ + (r'\s*(in|out|inout|buffer)\s+(\w+)\s*\(', 'port_array_param_type', 'array_range'), + (r'\s*(in|out|inout|buffer)\s+(\w+)[ \t\r\f\v]*', 'port_param_type'), + (r'\s*;\s*', None, '#pop'), + (r"\s*:=\s*([\w']+)", 'port_param_default'), + (r'--(.*)\n', 'line_comment'), + (r'\)\s*;\s*--(.*)\n', 'line_comment', '#pop:2'), + (r'\n\s*\)\s*;\s*--(.*)\n', 'port_list_comment', '#pop:2'), + (r'\n\s*', None), + (r'\)\s*;', 'end_port', '#pop:2'), + (r'--#(.*)\n', 'metacomment'), + (r'/\*', 'block_comment', 'block_comment'), + ], + 'array_range': [ + (r'\(', 'open_paren', 'nested_parens'), + (r'\s*([\w\+\-\*/\s]+)(\s+(?:down)?to)\s+([\w\+\-\*/\s]+)', 'array_range_val'), + (r'\)', 'array_range_end', '#pop'), + ], + 'nested_parens': [ + (r'\(', 'open_paren', 'nested_parens'), + (r'\s*([\w\+\-\*/\s]+)(\s+(?:down)?to)\s+([\w\+\-\*/\s]+)', 'array_range_val'), + (r'\)', 'close_paren', '#pop'), + ], + 'block_comment': [ + (r'\*/', 'end_comment', '#pop'), + ], } VhdlLexer = MiniLexer(vhdl_tokens, flags=re.MULTILINE | re.IGNORECASE) class VhdlObject(object): - """Base class for parsed VHDL objects + """Base class for parsed VHDL objects + + Args: + name (str): Name of the object + desc (str): Description from object metacomments + """ + + def __init__(self, name, desc=None): + self.name = name + self.kind = 'unknown' + self.desc = desc - Args: - name (str): Name of the object - desc (str): Description from object metacomments - """ - def __init__(self, name, desc=None): - self.name = name - self.kind = 'unknown' - self.desc = desc class VhdlParameter(object): - """Parameter to subprograms, ports, and generics - - Args: - name (str): Name of the object - mode (str): Direction mode for the parameter - data_type (str): Type name for the parameter - default_value (str): Default value of the parameter - desc (str): Description from object metacomments - param_desc (str): Description of the parameter - """ - def __init__(self, name, mode=None, data_type=None, default_value=None, desc=None, param_desc = None): - self.name = name - self.mode = mode - self.data_type = data_type - self.default_value = default_value - self.desc = desc - self.param_desc = None - - def __str__(self): - if self.mode is not None: - param = '{} : {} {}'.format(self.name, self.mode, self.data_type.name + self.data_type.arange) - else: - param = '{} : {}'.format(self.name, self.data_type.name + self.data_type.arange) - if self.default_value is not None: - param = '{} := {}'.format(param, self.default_value) - if self.param_desc is not None: - param = '{} --{}'.format(param, self.param_desc) - return param - - def __repr__(self): - return "VhdlParameter('{}', '{}', '{}')".format(self.name, self.mode, self.data_type.name + self.data_type.arange) + """Parameter to subprograms, ports, and generics + + Args: + name (str): Name of the object + mode (str): Direction mode for the parameter + data_type (str): Type name for the parameter + default_value (str): Default value of the parameter + desc (str): Description from object metacomments + param_desc (str): Description of the parameter + """ + + def __init__(self, name, mode=None, data_type=None, default_value=None, desc=None, param_desc=None): + self.name = name + self.mode = mode + self.data_type = data_type + self.default_value = default_value + self.desc = desc + self.param_desc = None + + def __str__(self): + if self.mode is not None: + param = '{} : {} {}'.format(self.name, self.mode, self.data_type.name + self.data_type.arange) + else: + param = '{} : {}'.format(self.name, self.data_type.name + self.data_type.arange) + if self.default_value is not None: + param = '{} := {}'.format(param, self.default_value) + if self.param_desc is not None: + param = '{} --{}'.format(param, self.param_desc) + return param + + def __repr__(self): + return "VhdlParameter('{}', '{}', '{}')".format(self.name, self.mode, + self.data_type.name + self.data_type.arange) + class VhdlParameterType(object): - """Parameter type definition - - Args: - name (str): Name of the type - direction(str): "to" or "downto" - r_bound (str): A simple expression based on digits or variable names - l_bound (str): A simple expression based on digits or variable names - arange (str): Original array range string - """ - def __init__(self, name, direction = "", r_bound = "", l_bound = "", arange = ""): - self.name = name - self.direction = direction.strip() - self.r_bound = r_bound.strip() - self.l_bound = l_bound.strip() - self.arange = arange - - def __repr__(self): - return "VhdlParameterType('{}','{}')".format(self.name, self.arange) + """Parameter type definition + + Args: + name (str): Name of the type + direction(str): "to" or "downto" + r_bound (str): A simple expression based on digits or variable names + l_bound (str): A simple expression based on digits or variable names + arange (str): Original array range string + """ + + def __init__(self, name, direction="", r_bound="", l_bound="", arange=""): + self.name = name + self.direction = direction.strip() + self.r_bound = r_bound.strip() + self.l_bound = l_bound.strip() + self.arange = arange + + def __repr__(self): + return "VhdlParameterType('{}','{}')".format(self.name, self.arange) + class VhdlPackage(VhdlObject): - """Package declaration + """Package declaration + + Args: + name (str): Name of the package + desc (str): Description from object metacomments + """ + + def __init__(self, name, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'package' - Args: - name (str): Name of the package - desc (str): Description from object metacomments - """ - def __init__(self, name, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'package' class VhdlType(VhdlObject): - """Type definition - - Args: - name (str): Name of the type - package (str): Package containing the type - type_of (str): Object type of this type definition - desc (str, optional): Description from object metacomments - """ - def __init__(self, name, package, type_of, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'type' - self.package = package - self.type_of = type_of - def __repr__(self): - return "VhdlType('{}', '{}')".format(self.name, self.type_of) + """Type definition + Args: + name (str): Name of the type + package (str): Package containing the type + type_of (str): Object type of this type definition + desc (str, optional): Description from object metacomments + """ -class VhdlSubtype(VhdlObject): - """Subtype definition - - Args: - name (str): Name of the subtype - package (str): Package containing the subtype - base_type (str): Base type name derived from - desc (str, optional): Description from object metacomments - """ - def __init__(self, name, package, base_type, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'subtype' - self.package = package - self.base_type = base_type - def __repr__(self): - return "VhdlSubtype('{}', '{}')".format(self.name, self.base_type) + def __init__(self, name, package, type_of, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'type' + self.package = package + self.type_of = type_of + def __repr__(self): + return "VhdlType('{}', '{}')".format(self.name, self.type_of) -class VhdlConstant(VhdlObject): - """Constant definition - - Args: - name (str): Name of the constant - package (str): Package containing the constant - base_type (str): Type fo the constant - desc (str, optional): Description from object metacomments - """ - def __init__(self, name, package, base_type, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'constant' - self.package = package - self.base_type = base_type - def __repr__(self): - return "VhdlConstant('{}', '{}')".format(self.name, self.base_type) +class VhdlSubtype(VhdlObject): + """Subtype definition -class VhdlFunction(VhdlObject): - """Function declaration - - Args: - name (str): Name of the function - package (str): Package containing the function - parameters (list of VhdlParameter): Parameters to the function - return_type (str, optional): Type of the return value - desc (str, optional): Description from object metacomments - """ - def __init__(self, name, package, parameters, return_type=None, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'function' - self.package = package - self.parameters = parameters - self.return_type = return_type - - def __repr__(self): - return "VhdlFunction('{}')".format(self.name) + Args: + name (str): Name of the subtype + package (str): Package containing the subtype + base_type (str): Base type name derived from + desc (str, optional): Description from object metacomments + """ + def __init__(self, name, package, base_type, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'subtype' + self.package = package + self.base_type = base_type -class VhdlProcedure(VhdlObject): - """Procedure declaration - - Args: - name (str): Name of the procedure - package (str): Package containing the procedure - parameters (list of VhdlParameter): Parameters to the procedure - desc (str, optional): Description from object metacomments - """ - def __init__(self, name, package, parameters, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'procedure' - self.package = package - self.parameters = parameters - - def __repr__(self): - return "VhdlProcedure('{}')".format(self.name) + def __repr__(self): + return "VhdlSubtype('{}', '{}')".format(self.name, self.base_type) -class VhdlEntity(VhdlObject): - """Entity declaration - Args: - name (str): Name of the entity - ports (list of VhdlParameter): Port parameters to the entity - generics (list of VhdlParameter): Generic parameters to the entity - sections (list of str): Metacomment sections - desc (str, optional): Description from object metacomments - """ - def __init__(self, name, ports, generics=None, sections=None, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'entity' - self.generics = generics if generics is not None else [] - self.ports = ports - self.sections = sections if sections is not None else {} - - def __repr__(self): - return "VhdlEntity('{}')".format(self.name) - - def dump(self): - print('VHDL entity: {}'.format(self.name)) - for p in self.ports: - print('\t{} ({}), {} ({})'.format(p.name, type(p.name), p.data_type, type(p.data_type))) -class VhdlComponent(VhdlObject): - """Component declaration - - Args: - name (str): Name of the component - package (str): Package containing the component - ports (list of VhdlParameter): Port parameters to the component - generics (list of VhdlParameter): Generic parameters to the component - sections (list of str): Metacomment sections - desc (str, optional): Description from object metacomments - """ - def __init__(self, name, package, ports, generics=None, sections=None, desc=None): - VhdlObject.__init__(self, name, desc) - self.kind = 'component' - self.package = package - self.generics = generics if generics is not None else [] - self.ports = ports - self.sections = sections if sections is not None else {} - - def __repr__(self): - return "VhdlComponent('{}')".format(self.name) - - def dump(self): - print('VHDL component: {}'.format(self.name)) - for p in self.ports: - print('\t{} ({}), {} ({})'.format(p.name, type(p.name), p.data_type, type(p.data_type))) +class VhdlConstant(VhdlObject): + """Constant definition + Args: + name (str): Name of the constant + package (str): Package containing the constant + base_type (str): Type fo the constant + desc (str, optional): Description from object metacomments + """ -def parse_vhdl_file(fname): - """Parse a named VHDL file + def __init__(self, name, package, base_type, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'constant' + self.package = package + self.base_type = base_type - Args: - fname(str): Name of file to parse - Returns: - Parsed objects. - """ - with open(fname, 'rt') as fh: - text = fh.read() - return parse_vhdl(text) + def __repr__(self): + return "VhdlConstant('{}', '{}')".format(self.name, self.base_type) -def parse_vhdl(text): - """Parse a text buffer of VHDL code - - Args: - text(str): Source code to parse - Returns: - Parsed objects. - """ - lex = VhdlLexer - - name = None - kind = None - saved_type = None - end_param_group = False - cur_package = None - - metacomments = [] - parameters = [] - param_items = [] - - generics = [] - ports = [] - sections = [] - port_param_index = 0 - last_items = [] - array_range_start_pos = 0 - - objects = [] - - for pos, action, groups in lex.run(text): - if action == 'metacomment': - realigned = re.sub(r'^#+', lambda m: ' ' * len(m.group(0)), groups[0]) - if not last_items: - metacomments.append(realigned) - else: - for i in last_items: - i.desc = realigned - if action == 'section_meta': - sections.append((port_param_index, groups[0])) - - elif action == 'function': - kind = 'function' - name = groups[0] - param_items = [] - parameters = [] - elif action == 'procedure': - kind = 'procedure' - name = groups[0] - param_items = [] - parameters = [] - elif action == 'param': - if end_param_group: - # Complete previous parameters - for i in param_items: - parameters.append(i) - param_items = [] - end_param_group = False - - param_items.append(VhdlParameter(groups[1])) - elif action == 'param_type': - mode, ptype = groups - - if mode is not None: - mode = mode.strip() - - for i in param_items: # Set mode and type for all pending parameters - i.mode = mode - i.data_type = ptype - - end_param_group = True - - elif action == 'param_default': - for i in param_items: - i.default_value = groups[0] - - elif action == 'end_subprogram': - # Complete last parameters - for i in param_items: - parameters.append(i) - - if kind == 'function': - vobj = VhdlFunction(name, cur_package, parameters, groups[0], metacomments) - else: - vobj = VhdlProcedure(name, cur_package, parameters, metacomments) - - objects.append(vobj) - - metacomments = [] - parameters = [] - param_items = [] - kind = None - name = None - - elif action == 'entity': - kind = 'entity' - name = groups[0] - generics = [] - ports = [] - param_items = [] - sections = [] - port_param_index = 0 - - elif action == 'component': - kind = 'component' - name = groups[0] - generics = [] - ports = [] - param_items = [] - sections = [] - port_param_index = 0 - - elif action == 'generic_param': - param_items.append(groups[0]) - - elif action == 'generic_param_type': - ptype = groups[0] - last_items = [] - for i in param_items: - p = VhdlParameter(i, 'in', VhdlParameterType(ptype)) - generics.append(p) - last_items.append(p) - - param_items = [] - - elif action == 'generic_param_default': - for i in last_items: - i.default_value = groups[0] - - elif action == 'port_param': - param_items.append(groups[0]) - port_param_index += 1 - - elif action == 'port_param_type': - mode, ptype = groups - - last_items = [] - for i in param_items: - p = VhdlParameter(i, mode, VhdlParameterType(ptype)) - ports.append(p) - last_items.append(p) - - param_items = [] - - elif action == 'port_param_default': - for i in last_items: - i.default_value = groups[0] - - elif action == 'port_array_param_type': - mode, ptype = groups - array_range_start_pos = pos[1] - - elif action == 'array_range_val': - l_bound, direction, r_bound = groups - - elif action == 'array_range_end': - arange = text[array_range_start_pos:pos[0]+1] - - last_items = [] - for i in param_items: - p = VhdlParameter(i, mode, VhdlParameterType(ptype, direction, r_bound, l_bound, arange)) - ports.append(p) - last_items.append(p) - - param_items = [] - - elif action == 'end_entity': - vobj = VhdlEntity(name, ports, generics, dict(sections), metacomments) - objects.append(vobj) - last_items = [] - metacomments = [] - - elif action == 'end_component': - vobj = VhdlComponent(name, cur_package, ports, generics, dict(sections), metacomments) - objects.append(vobj) - last_items = [] - metacomments = [] - - elif action == 'package': - objects.append(VhdlPackage(groups[0])) - cur_package = groups[0] - kind = None - name = None - - elif action == 'type': - saved_type = groups[0] - - elif action in ('array_type', 'file_type', 'access_type', 'record_type', 'range_type', 'enum_type', 'incomplete_type'): - vobj = VhdlType(saved_type, cur_package, action, metacomments) - objects.append(vobj) - kind = None - name = None - metacomments = [] - - elif action == 'subtype': - vobj = VhdlSubtype(groups[0], cur_package, groups[1], metacomments) - objects.append(vobj) - kind = None - name = None - metacomments = [] - - elif action == 'constant': - vobj = VhdlConstant(groups[0], cur_package, groups[1], metacomments) - objects.append(vobj) - kind = None - name = None - metacomments = [] - - elif action == 'line_comment': - for i in last_items: - if not i.param_desc: - i.param_desc = groups[0] - - return objects +class VhdlFunction(VhdlObject): + """Function declaration -def subprogram_prototype(vo): - """Generate a canonical prototype string + Args: + name (str): Name of the function + package (str): Package containing the function + parameters (list of VhdlParameter): Parameters to the function + return_type (str, optional): Type of the return value + desc (str, optional): Description from object metacomments + """ - Args: - vo (VhdlFunction, VhdlProcedure): Subprogram object - Returns: - Prototype string. - """ + def __init__(self, name, package, parameters, return_type=None, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'function' + self.package = package + self.parameters = parameters + self.return_type = return_type - plist = '; '.join(str(p) for p in vo.parameters) + def __repr__(self): + return "VhdlFunction('{}')".format(self.name) - if isinstance(vo, VhdlFunction): - if len(vo.parameters) > 0: - proto = 'function {}({}) return {};'.format(vo.name, plist, vo.return_type) - else: - proto = 'function {} return {};'.format(vo.name, vo.return_type) - else: # procedure - proto = 'procedure {}({});'.format(vo.name, plist) +class VhdlProcedure(VhdlObject): + """Procedure declaration - return proto + Args: + name (str): Name of the procedure + package (str): Package containing the procedure + parameters (list of VhdlParameter): Parameters to the procedure + desc (str, optional): Description from object metacomments + """ -def subprogram_signature(vo, fullname=None): - """Generate a signature string + def __init__(self, name, package, parameters, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'procedure' + self.package = package + self.parameters = parameters - Args: - vo (VhdlFunction, VhdlProcedure): Subprogram object - Returns: - Signature string. - """ + def __repr__(self): + return "VhdlProcedure('{}')".format(self.name) - if fullname is None: - fullname = vo.name - if isinstance(vo, VhdlFunction): - plist = ','.join(p.data_type for p in vo.parameters) - sig = '{}[{} return {}]'.format(fullname, plist, vo.return_type) - else: # procedure - plist = ','.join(p.data_type for p in vo.parameters) - sig = '{}[{}]'.format(fullname, plist) +class VhdlEntity(VhdlObject): + """Entity declaration + Args: + name (str): Name of the entity + ports (list of VhdlParameter): Port parameters to the entity + generics (list of VhdlParameter): Generic parameters to the entity + sections (list of str): Metacomment sections + desc (str, optional): Description from object metacomments + """ - return sig + def __init__(self, name, ports, generics=None, sections=None, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'entity' + self.generics = generics if generics is not None else [] + self.ports = ports + self.sections = sections if sections is not None else {} + def __repr__(self): + return "VhdlEntity('{}')".format(self.name) -def is_vhdl(fname): - """Identify file as VHDL by its extension + def dump(self): + print('VHDL entity: {}'.format(self.name)) + for p in self.ports: + print('\t{} ({}), {} ({})'.format(p.name, type(p.name), p.data_type, type(p.data_type))) - Args: - fname (str): File name to check - Returns: - True when file has a VHDL extension. - """ - return os.path.splitext(fname)[1].lower() in ('.vhdl', '.vhd') +class VhdlComponent(VhdlObject): + """Component declaration -class VhdlExtractor(object): - """Utility class that caches parsed objects and tracks array type definitions + Args: + name (str): Name of the component + package (str): Package containing the component + ports (list of VhdlParameter): Port parameters to the component + generics (list of VhdlParameter): Generic parameters to the component + sections (list of str): Metacomment sections + desc (str, optional): Description from object metacomments + """ + + def __init__(self, name, package, ports, generics=None, sections=None, desc=None): + VhdlObject.__init__(self, name, desc) + self.kind = 'component' + self.package = package + self.generics = generics if generics is not None else [] + self.ports = ports + self.sections = sections if sections is not None else {} - Args: - array_types(set): Initial array types - """ - def __init__(self, array_types=set()): - self.array_types = set(('std_ulogic_vector', 'std_logic_vector', - 'signed', 'unsigned', 'bit_vector')) + def __repr__(self): + return "VhdlComponent('{}')".format(self.name) - self.array_types |= array_types - self.object_cache = {} + def dump(self): + print('VHDL component: {}'.format(self.name)) + for p in self.ports: + print('\t{} ({}), {} ({})'.format(p.name, type(p.name), p.data_type, type(p.data_type))) - def extract_objects(self, fname, type_filter=None): - """Extract objects from a source file + +def parse_vhdl_file(fname): + """Parse a named VHDL file Args: - fname (str): File to parse - type_filter (class, optional): Object class to filter results + fname(str): Name of file to parse Returns: - List of parsed objects. + Parsed objects. """ - objects = [] - if fname in self.object_cache: - objects = self.object_cache[fname] - else: - with io.open(fname, 'rt', encoding='latin-1') as fh: + with open(fname, 'rt') as fh: text = fh.read() - objects = parse_vhdl(text) - self.object_cache[fname] = objects - self._register_array_types(objects) - - if type_filter: - objects = [o for o in objects if isinstance(o, type_filter)] + return parse_vhdl(text) - return objects - def extract_objects_from_source(self, text, type_filter=None): - """Extract object declarations from a text buffer +def parse_vhdl(text): + """Parse a text buffer of VHDL code Args: - text (str): Source code to parse - type_filter (class, optional): Object class to filter results + text(str): Source code to parse Returns: - List of parsed objects. + Parsed objects. """ - objects = parse_vhdl(text) - self._register_array_types(objects) + lex = VhdlLexer + + name = None + kind = None + saved_type = None + end_param_group = False + cur_package = None + + metacomments = [] + parameters = [] + param_items = [] - if type_filter: - objects = [o for o in objects if isinstance(o, type_filter)] + generics = [] + ports = [] + sections = [] + port_param_index = 0 + last_items = [] + array_range_start_pos = 0 + + objects = [] + + for pos, action, groups in lex.run(text): + if action == 'metacomment': + realigned = re.sub(r'^#+', lambda m: ' ' * len(m.group(0)), groups[0]) + if not last_items: + metacomments.append(realigned) + else: + for i in last_items: + i.desc = realigned + if action == 'section_meta': + sections.append((port_param_index, groups[0])) + + elif action == 'function': + kind = 'function' + name = groups[0] + param_items = [] + parameters = [] + elif action == 'procedure': + kind = 'procedure' + name = groups[0] + param_items = [] + parameters = [] + elif action == 'param': + if end_param_group: + # Complete previous parameters + for i in param_items: + parameters.append(i) + param_items = [] + end_param_group = False + + param_items.append(VhdlParameter(groups[1])) + elif action == 'param_type': + mode, ptype = groups + + if mode is not None: + mode = mode.strip() + + for i in param_items: # Set mode and type for all pending parameters + i.mode = mode + i.data_type = ptype + + end_param_group = True + + elif action == 'param_default': + for i in param_items: + i.default_value = groups[0] + + elif action == 'end_subprogram': + # Complete last parameters + for i in param_items: + parameters.append(i) + + if kind == 'function': + vobj = VhdlFunction(name, cur_package, parameters, groups[0], metacomments) + else: + vobj = VhdlProcedure(name, cur_package, parameters, metacomments) + + objects.append(vobj) + + metacomments = [] + parameters = [] + param_items = [] + kind = None + name = None + + elif action == 'entity': + kind = 'entity' + name = groups[0] + generics = [] + ports = [] + param_items = [] + sections = [] + port_param_index = 0 + + elif action == 'component': + kind = 'component' + name = groups[0] + generics = [] + ports = [] + param_items = [] + sections = [] + port_param_index = 0 + + elif action == 'generic_param': + param_items.append(groups[0]) + + elif action == 'generic_param_type': + ptype = groups[0] + last_items = [] + for i in param_items: + p = VhdlParameter(i, 'in', VhdlParameterType(ptype)) + generics.append(p) + last_items.append(p) + + param_items = [] + + elif action == 'generic_param_default': + for i in last_items: + i.default_value = groups[0] + + elif action == 'port_param': + param_items.append(groups[0]) + port_param_index += 1 + + elif action == 'port_param_type': + mode, ptype = groups + + last_items = [] + for i in param_items: + p = VhdlParameter(i, mode, VhdlParameterType(ptype)) + ports.append(p) + last_items.append(p) + + param_items = [] + + elif action == 'port_param_default': + for i in last_items: + i.default_value = groups[0] + + elif action == 'port_array_param_type': + mode, ptype = groups + array_range_start_pos = pos[1] + + elif action == 'array_range_val': + l_bound, direction, r_bound = groups + + elif action == 'array_range_end': + arange = text[array_range_start_pos:pos[0] + 1] + + last_items = [] + for i in param_items: + p = VhdlParameter(i, mode, VhdlParameterType(ptype, direction, r_bound, l_bound, arange)) + ports.append(p) + last_items.append(p) + + param_items = [] + + elif action == 'end_entity': + vobj = VhdlEntity(name, ports, generics, dict(sections), metacomments) + objects.append(vobj) + last_items = [] + metacomments = [] + + elif action == 'end_component': + vobj = VhdlComponent(name, cur_package, ports, generics, dict(sections), metacomments) + objects.append(vobj) + last_items = [] + metacomments = [] + + elif action == 'package': + objects.append(VhdlPackage(groups[0])) + cur_package = groups[0] + kind = None + name = None + + elif action == 'type': + saved_type = groups[0] + + elif action in ( + 'array_type', 'file_type', 'access_type', 'record_type', 'range_type', 'enum_type', 'incomplete_type'): + vobj = VhdlType(saved_type, cur_package, action, metacomments) + objects.append(vobj) + kind = None + name = None + metacomments = [] + + elif action == 'subtype': + vobj = VhdlSubtype(groups[0], cur_package, groups[1], metacomments) + objects.append(vobj) + kind = None + name = None + metacomments = [] + + elif action == 'constant': + vobj = VhdlConstant(groups[0], cur_package, groups[1], metacomments) + objects.append(vobj) + kind = None + name = None + metacomments = [] + + elif action == 'line_comment': + for i in last_items: + if not i.param_desc: + i.param_desc = groups[0] return objects - def is_array(self, data_type): - """Check if a type is a known array type +def subprogram_prototype(vo): + """Generate a canonical prototype string Args: - data_type (str): Name of type to check + vo (VhdlFunction, VhdlProcedure): Subprogram object Returns: - True if ``data_type`` is a known array type. + Prototype string. """ - # Split off any brackets - data_type = data_type.split('[')[0].strip() + plist = '; '.join(str(p) for p in vo.parameters) - return data_type.lower() in self.array_types + if isinstance(vo, VhdlFunction): + if len(vo.parameters) > 0: + proto = 'function {}({}) return {};'.format(vo.name, plist, vo.return_type) + else: + proto = 'function {} return {};'.format(vo.name, vo.return_type) + else: # procedure + proto = 'procedure {}({});'.format(vo.name, plist) - def _add_array_types(self, type_defs): - """Add array data types to internal registry + return proto - Args: - type_defs (dict): Dictionary of type definitions - """ - if 'arrays' in type_defs: - self.array_types |= set(type_defs['arrays']) - def load_array_types(self, fname): - """Load file of previously extracted data types +def subprogram_signature(vo, fullname=None): + """Generate a signature string Args: - fname (str): Name of file to load array database from + vo (VhdlFunction, VhdlProcedure): Subprogram object + Returns: + Signature string. """ - type_defs = '' - with open(fname, 'rt') as fh: - type_defs = fh.read() - try: - type_defs = ast.literal_eval(type_defs) - except SyntaxError: - type_defs = {} + if fullname is None: + fullname = vo.name - self._add_array_types(type_defs) + if isinstance(vo, VhdlFunction): + plist = ','.join(p.data_type for p in vo.parameters) + sig = '{}[{} return {}]'.format(fullname, plist, vo.return_type) + else: # procedure + plist = ','.join(p.data_type for p in vo.parameters) + sig = '{}[{}]'.format(fullname, plist) - def save_array_types(self, fname): - """Save array type registry to a file + return sig + + +def is_vhdl(fname): + """Identify file as VHDL by its extension Args: - fname (str): Name of file to save array database to + fname (str): File name to check + Returns: + True when file has a VHDL extension. """ - type_defs = {'arrays': sorted(list(self.array_types))} - with open(fname, 'wt') as fh: - pprint(type_defs, stream=fh) + return os.path.splitext(fname)[1].lower() in ('.vhdl', '.vhd') + - def _register_array_types(self, objects): - """Add array type definitions to internal registry +class VhdlExtractor(object): + """Utility class that caches parsed objects and tracks array type definitions Args: - objects (list of VhdlType or VhdlSubtype): Array types to track + array_types(set): Initial array types """ - # Add all array types directly - types = [o for o in objects if isinstance(o, VhdlType) and o.type_of == 'array_type'] - for t in types: - self.array_types.add(t.name) - subtypes = {o.name:o.base_type for o in objects if isinstance(o, VhdlSubtype)} + def __init__(self, array_types=set()): + self.array_types = set(('std_ulogic_vector', 'std_logic_vector', + 'signed', 'unsigned', 'bit_vector')) + + self.array_types |= array_types + self.object_cache = {} + + def extract_objects(self, fname, type_filter=None): + """Extract objects from a source file + + Args: + fname (str): File to parse + type_filter (class, optional): Object class to filter results + Returns: + List of parsed objects. + """ + objects = [] + if fname in self.object_cache: + objects = self.object_cache[fname] + else: + with io.open(fname, 'rt', encoding='latin-1') as fh: + text = fh.read() + objects = parse_vhdl(text) + self.object_cache[fname] = objects + self._register_array_types(objects) + + if type_filter: + objects = [o for o in objects if isinstance(o, type_filter)] + + return objects + + def extract_objects_from_source(self, text, type_filter=None): + """Extract object declarations from a text buffer + + Args: + text (str): Source code to parse + type_filter (class, optional): Object class to filter results + Returns: + List of parsed objects. + """ + objects = parse_vhdl(text) + self._register_array_types(objects) - # Find all subtypes of an array type - for k,v in subtypes.items(): - while v in subtypes: # Follow subtypes of subtypes - v = subtypes[v] - if v in self.array_types: - self.array_types.add(k) + if type_filter: + objects = [o for o in objects if isinstance(o, type_filter)] - def register_array_types_from_sources(self, source_files): - """Add array type definitions from a file list to internal registry + return objects - Args: - source_files (list of str): Files to parse for array definitions - """ - for fname in source_files: - if is_vhdl(fname): - self._register_array_types(self.extract_objects(fname)) + def is_array(self, data_type): + """Check if a type is a known array type + + Args: + data_type (str): Name of type to check + Returns: + True if ``data_type`` is a known array type. + """ + + # Split off any brackets + data_type = data_type.split('[')[0].strip() + + return data_type.lower() in self.array_types + + def _add_array_types(self, type_defs): + """Add array data types to internal registry + + Args: + type_defs (dict): Dictionary of type definitions + """ + if 'arrays' in type_defs: + self.array_types |= set(type_defs['arrays']) + + def load_array_types(self, fname): + """Load file of previously extracted data types + + Args: + fname (str): Name of file to load array database from + """ + type_defs = '' + with open(fname, 'rt') as fh: + type_defs = fh.read() + + try: + type_defs = ast.literal_eval(type_defs) + except SyntaxError: + type_defs = {} + + self._add_array_types(type_defs) + + def save_array_types(self, fname): + """Save array type registry to a file + + Args: + fname (str): Name of file to save array database to + """ + type_defs = {'arrays': sorted(list(self.array_types))} + with open(fname, 'wt') as fh: + pprint(type_defs, stream=fh) + + def _register_array_types(self, objects): + """Add array type definitions to internal registry + + Args: + objects (list of VhdlType or VhdlSubtype): Array types to track + """ + # Add all array types directly + types = [o for o in objects if isinstance(o, VhdlType) and o.type_of == 'array_type'] + for t in types: + self.array_types.add(t.name) + + subtypes = {o.name: o.base_type for o in objects if isinstance(o, VhdlSubtype)} + + # Find all subtypes of an array type + for k, v in subtypes.items(): + while v in subtypes: # Follow subtypes of subtypes + v = subtypes[v] + if v in self.array_types: + self.array_types.add(k) + + def register_array_types_from_sources(self, source_files): + """Add array type definitions from a file list to internal registry + + Args: + source_files (list of str): Files to parse for array definitions + """ + for fname in source_files: + if is_vhdl(fname): + self._register_array_types(self.extract_objects(fname)) if __name__ == '__main__': - ve = VhdlExtractor() - code = ''' + ve = VhdlExtractor() + code = ''' package foo is function afunc(q,w,e : std_ulogic; h,j,k : unsigned) return std_ulogic; @@ -817,18 +840,18 @@ def register_array_types_from_sources(self, source_files): end package; ''' - objs = ve.extract_objects_from_source(code) - - for o in objs: - print(o.name) - try: - for p in o.parameters: - print(p) - except: - pass - - try: - for p in o.ports: - print(p) - except: - pass + objs = ve.extract_objects_from_source(code) + + for o in objs: + print(o.name) + try: + for p in o.parameters: + print(p) + except: + pass + + try: + for p in o.ports: + print(p) + except: + pass From 37de2fb050e61a4458c20176ef1cdd20bfaa922a Mon Sep 17 00:00:00 2001 From: michael-etzkorn Date: Sun, 28 Nov 2021 09:46:02 -0600 Subject: [PATCH 5/6] VHDL documentation parser in single quotes wasn't complained about --- hdlparse/vhdl_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hdlparse/vhdl_parser.py b/hdlparse/vhdl_parser.py index e363b67..260a505 100644 --- a/hdlparse/vhdl_parser.py +++ b/hdlparse/vhdl_parser.py @@ -8,7 +8,7 @@ from pprint import pprint from hdlparse.minilexer import MiniLexer -'''VHDL documentation parser''' +"""VHDL documentation parser""" vhdl_tokens = { 'root': [ From 0c7e3333251bb39457767ff18c6a4ee02b02c116 Mon Sep 17 00:00:00 2001 From: michael-etzkorn Date: Sun, 28 Nov 2021 10:21:48 -0600 Subject: [PATCH 6/6] Removed python 2 style class declaration --- hdlparse/verilog_parser.py | 6 +++--- hdlparse/vhdl_parser.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hdlparse/verilog_parser.py b/hdlparse/verilog_parser.py index d7008da..7cbfa89 100644 --- a/hdlparse/verilog_parser.py +++ b/hdlparse/verilog_parser.py @@ -59,7 +59,7 @@ VerilogLexer = MiniLexer(verilog_tokens) -class VerilogObject(object): +class VerilogObject: """Base class for parsed Verilog objects""" def __init__(self, name, desc=None): @@ -68,7 +68,7 @@ def __init__(self, name, desc=None): self.desc = [] if desc is None else desc -class VerilogParameter(object): +class VerilogParameter: """Parameter and port to a module""" def __init__(self, name, mode=None, data_type=None, default_value=None, desc=None): @@ -229,7 +229,7 @@ def is_verilog(fname): return os.path.splitext(fname)[1].lower() in ('.vlog', '.v') -class VerilogExtractor(object): +class VerilogExtractor: """Utility class that caches parsed objects""" def __init__(self): diff --git a/hdlparse/vhdl_parser.py b/hdlparse/vhdl_parser.py index 260a505..b8aade5 100644 --- a/hdlparse/vhdl_parser.py +++ b/hdlparse/vhdl_parser.py @@ -157,7 +157,7 @@ VhdlLexer = MiniLexer(vhdl_tokens, flags=re.MULTILINE | re.IGNORECASE) -class VhdlObject(object): +class VhdlObject: """Base class for parsed VHDL objects Args: @@ -171,7 +171,7 @@ def __init__(self, name, desc=None): self.desc = desc -class VhdlParameter(object): +class VhdlParameter: """Parameter to subprograms, ports, and generics Args: @@ -207,7 +207,7 @@ def __repr__(self): self.data_type.name + self.data_type.arange) -class VhdlParameterType(object): +class VhdlParameterType: """Parameter type definition Args: @@ -684,7 +684,7 @@ def is_vhdl(fname): return os.path.splitext(fname)[1].lower() in ('.vhdl', '.vhd') -class VhdlExtractor(object): +class VhdlExtractor: """Utility class that caches parsed objects and tracks array type definitions Args: