From 7e1fe0ee5f333f560490c0d6a5bae4073f731dc9 Mon Sep 17 00:00:00 2001 From: Olof Kraigher Date: Wed, 8 Jul 2015 17:55:16 +0200 Subject: [PATCH] Made vhdl parser tolerate things not starting on a new line. Issue #58. --- vunit/test/unit/test_vhdl_parser.py | 40 +++++++++++++++++++++ vunit/vhdl_parser.py | 55 +++++++++++------------------ 2 files changed, 60 insertions(+), 35 deletions(-) diff --git a/vunit/test/unit/test_vhdl_parser.py b/vunit/test/unit/test_vhdl_parser.py index 3223bdfe4..18ac2432b 100644 --- a/vunit/test/unit/test_vhdl_parser.py +++ b/vunit/test/unit/test_vhdl_parser.py @@ -139,6 +139,46 @@ def test_parsing_entity_with_generics(self): self.assertEqual(generics[1].subtype_indication.code, "boolean") self.assertEqual(generics[1].subtype_indication.type_mark, "boolean") + def test_parsing_entity_with_generics_corner_cases(self): + self.parse_single_entity("""\ +entity name is end entity; +""") + + entity = self.parse_single_entity("""\ +entity name is generic(g : t); end entity; +""") + self.assertEqual(len(entity.generics), 1) + self.assertEqual(entity.generics[0].identifier, "g") + + entity = self.parse_single_entity("""\ +entity name is generic +( +g : t +); +end entity; +""") + self.assertEqual(len(entity.generics), 1) + self.assertEqual(entity.generics[0].identifier, "g") + + entity = self.parse_single_entity("""\ +end architecture; entity name is generic +( +g : t +); +end entity; +""") + self.assertEqual(len(entity.generics), 1) + self.assertEqual(entity.generics[0].identifier, "g") + + entity = self.parse_single_entity("""\ +entity name is foo_generic +( +g : t +); +end entity; +""") + self.assertEqual(len(entity.generics), 0) + def test_parsing_entity_with_ports(self): entity = self.parse_single_entity("""\ entity name is diff --git a/vunit/vhdl_parser.py b/vunit/vhdl_parser.py index 3be17f826..cf834e5fc 100644 --- a/vunit/vhdl_parser.py +++ b/vunit/vhdl_parser.py @@ -121,8 +121,7 @@ def __init__(self, identifier): self.identifier = identifier _package_body_pattern = re.compile(r""" - (^|\A) # Beginning of line or start of string - \s* # Potential whitespaces + \b # Word boundary package # package keyword \s+ # At least one whitespace body # body keyword @@ -151,8 +150,7 @@ def __init__(self, identifier, entity): self.entity = entity _configuration_re = re.compile(r""" - (^|\A) # Beginning of line or start of string - \s* # Potential whitespaces + \b # Word boundary configuration # configuration keyword \s+ # At least one whitespace (?P[a-zA-Z][\w]*) # An identifier @@ -182,8 +180,7 @@ def __init__(self, identifier, entity): self.entity = entity _architecture_re = re.compile(r""" - (^|\A) # Beginning of line or start of string - \s* # Potential whitespaces + \b # Word boundary architecture # architecture keyword \s+ # At least one whitespace (?P[a-zA-Z][\w]*) # An identifier @@ -219,8 +216,7 @@ def __init__(self, identifier, constant_declarations, # pylint: disable=too-man self.array_types = array_types _package_start_re = re.compile(r""" - (^|\A) # Beginning of line or start of string - \s* # Potential whitespaces + \b # Word boundary package # package keyword \s+ # At least one whitespace (?P[a-zA-Z][\w]*) # An identifier @@ -236,8 +232,7 @@ def find(cls, code): for package in cls._package_start_re.finditer(code): identifier = package.group('id') package_end = re.compile(r""" - (^|\A) # Beginning of line or start of string - [\s]* # Potential whitespaces + \b # Word boundary end # end keyword (\s+package)? # Optional package keyword (\s+""" + identifier + r""")? # Optional identifier @@ -321,8 +316,7 @@ def add_port(self, identifier, mode, subtype_code, init_value=None): mode=mode)) _entity_start_re = re.compile(r""" - (^|\A) # Beginning of line or start of string - \s* # Potential whitespaces + \b # Word boundary entity # entity keyword \s+ # At least one whitespace (?P[a-zA-Z][\w]*) # An identifier @@ -338,10 +332,8 @@ def find(cls, code): for entity in cls._entity_start_re.finditer(code): identifier = entity.group('id') sub_code = code[entity.start():] - entity_end_re = re.compile(r""" - (^|\A) # Beginning of line or start of string - [\s]* # Potential whitespaces + \b # Word boundary end # end keyword [\s]* # Potential whitespaces (entity)? # Optional entity keyword @@ -363,8 +355,7 @@ def parse(cls, code): # Extract identifier re_flags = re.MULTILINE | re.IGNORECASE | re.VERBOSE entity_start = re.compile(r""" - \A # Start of string - \s* # Potential whitespaces + \b # Word boundary entity # entity keyword \s+ # At least one whitespace (?P[a-zA-Z][\w]*) # An identifier @@ -385,11 +376,10 @@ def _find_generic_clause(cls, code): """ re_flags = re.MULTILINE | re.IGNORECASE | re.VERBOSE generic_clause_start = re.compile(r""" - ^ # Beginning of line - [\s]* # Potential whitespaces - generic # generic keyword - [\s]* # Potential whitespaces - \( # Opening parenthesis + \b # Word boundary + generic # generic keyword + [\s]* # Potential whitespaces + \( # Opening parenthesis """, re_flags) match = generic_clause_start.search(code) if match: @@ -475,9 +465,8 @@ def __init__(self, identifier): self.identifier = identifier _context_start_re = re.compile(r""" - (^|\A) # Beginning of line or start of string - \s* # Potential whitespaces - context # context keyword + \b # Word boundary + context # context keyword \s+ # At least one whitespace (?P[a-zA-Z][\w]*) # An identifier \s+ # At least one whitespace @@ -654,8 +643,7 @@ def __init__(self, identifier, literals): self.literals = literals _enum_declaration_re = re.compile(r""" - (^|\A) # Beginning of line or start of string - \s* + \b # Word boundary type \s+ (?P[a-zA-Z][\w]*) # An identifier @@ -688,8 +676,7 @@ def __init__(self, identifier, elements): self.elements = elements _record_declaration_re = re.compile(r""" - (^|\A) # Beginning of line or start of string - \s* + \b # Word boundary type \s+ (?P[a-zA-Z][\w]*) # An identifier @@ -763,8 +750,7 @@ def __init__(self, identifier, subtype_indication, range1, range2): \s+range\s+<>\s*""", re.MULTILINE | re.IGNORECASE | re.VERBOSE | re.DOTALL) _array_declaration_re = re.compile(r""" - (^|\A) - \s* + \b # Word boundary type \s+ (?P[a-zA-Z][\w]*) @@ -865,8 +851,7 @@ class VHDLReference(object): "configuration") _uses_re = re.compile(r""" - (^|\A) # Beginning of line or start of string - \s* # Potential whitespaces + \b # Word boundary (?Puse|context) # use or context keyword \s+ # At least one whitespace (?P[a-zA-Z][\w]*(\.[a-zA-Z][\w]*){1,2}) @@ -913,7 +898,7 @@ def get_ids(match): return references _entity_reference_re = re.compile( - r'(^|\A|\s)\s*entity\s+(?P[a-zA-Z]\w*)\.(?P[a-zA-Z]\w*)\s*(\((?P[a-zA-Z]\w*)\))?', + r'\bentity\s+(?P[a-zA-Z]\w*)\.(?P[a-zA-Z]\w*)\s*(\((?P[a-zA-Z]\w*)\))?', re.MULTILINE | re.IGNORECASE) @classmethod @@ -930,7 +915,7 @@ def _find_entity_references(cls, code): return references _configuration_reference_re = re.compile( - r'(^|\A|\s)\s*configuration\s+(?P[a-zA-Z]\w*)\.(?P[a-zA-Z]\w*)', + r'\bconfiguration\s+(?P[a-zA-Z]\w*)\.(?P[a-zA-Z]\w*)', re.MULTILINE | re.IGNORECASE) @classmethod