From 16280cc1df2ac4c5e872a761d2cf6276cf1ef0d3 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 2 Aug 2021 12:49:10 +0200 Subject: [PATCH] several bugfixes and improvements --- parserbase/file_list_parser.py | 28 +++++++------- parserbase/parser.py | 11 ++++++ returnvalues/returnvalues_parser.py | 60 +++++++++++++++++++++-------- 3 files changed, 70 insertions(+), 29 deletions(-) diff --git a/parserbase/file_list_parser.py b/parserbase/file_list_parser.py index 2169474..f6101d9 100644 --- a/parserbase/file_list_parser.py +++ b/parserbase/file_list_parser.py @@ -1,37 +1,37 @@ -""" -@file file_list_parser.py -@brief Generic File Parser class -@details +"""Generic File Parser class Used by parse header files. Implemented as class in case header parser becomes more complex -@author R. Mueller -@date 22.11.2019 """ import os import re from typing import Union +from fsfwgen.core import get_console_logger + +LOGGER = get_console_logger() + # pylint: disable=too-few-public-methods class FileListParser: - """ - Generic header parser which takes a directory name or directory name list + """Generic header parser which takes a directory name or directory name list and parses all included header files recursively. + TODO: Filter functionality for each directory to filter out files or folders """ def __init__(self, directory_list_or_name: Union[str, list]): + self.directory_list = [] if isinstance(directory_list_or_name, str): - self.directory_list = [directory_list_or_name] + self.directory_list.append(directory_list_or_name) elif isinstance(directory_list_or_name, list): - self.directory_list = directory_list_or_name + self.directory_list.extend(directory_list_or_name) else: - print("Header Parser: Passed directory list is not a header name or list of " - "header names") + LOGGER.warning( + "Header Parser: Passed directory list is not a header name or list of header names" + ) self.header_files = [] def parse_header_files(self, search_recursively: bool = False, printout_string: str = "Parsing header files: ", print_current_dir: bool = False): - """ - This function is called to get a list of header files + """This function is called to get a list of header files :param search_recursively: :param printout_string: :param print_current_dir: diff --git a/parserbase/parser.py b/parserbase/parser.py index 71a7df0..a29fa2c 100644 --- a/parserbase/parser.py +++ b/parserbase/parser.py @@ -17,6 +17,12 @@ from abc import abstractmethod from typing import Dict, List +class VerbosityLevels(enum.Enum): + REDUCED = 0, + REGULAR = 1, + DEBUG = 2 + + class FileParserModes(enum.Enum): REGULAR = enum.auto(), MOVING_WINDOW = enum.auto() @@ -72,6 +78,9 @@ class FileParser: def set_verbosity(self, verbose_level: int): self._verbose_level = verbose_level + def get_verbosity(self): + return self._verbose_level + def enable_moving_window_debugging(self, file_name: str): self.__debug_moving_window = True self.__debug_moving_window_filename = file_name @@ -201,6 +210,8 @@ class FileParser: def _build_multi_line_string_generic( self, first_line: str, moving_window: List[str] ) -> str: + """This function transforms a multi line match into a one line match by searching for the + semicolon at the string end""" all_lines = first_line.rstrip() end_found = False current_idx = self._moving_window_center_idx diff --git a/returnvalues/returnvalues_parser.py b/returnvalues/returnvalues_parser.py index 3425ee2..29e4cc5 100644 --- a/returnvalues/returnvalues_parser.py +++ b/returnvalues/returnvalues_parser.py @@ -2,19 +2,21 @@ import re import sys from typing import List, Tuple -from fsfwgen.parserbase.parser import FileParser +from fsfwgen.parserbase.parser import FileParser, VerbosityLevels from fsfwgen.utility.printer import PrettyPrinter +from fsfwgen.core import get_console_logger + +LOGGER = get_console_logger() # Intermediate solution MAX_STRING_LEN = 80 PRINT_TRUNCATED_ENTRIES = False -DEBUG_INTERFACE_ID_COMPARISON = False DEBUG_FOR_FILE_NAME = False -DEBUG_FILE_NAME = "RingBufferAnalyzer" CLASS_ID_NAMESPACE = "CLASS_ID" DEFAULT_MOVING_WINDOWS_SIZE = 7 +INVALID_IF_ID = -1 class InterfaceParser(FileParser): @@ -26,6 +28,10 @@ class InterfaceParser(FileParser): self.file_name_table = [] self.start_name_list = [] self.end_name_list = [] + self._debug_mode = False + + def enable_debug_mode(self, enable: bool): + self._debug_mode = enable def _handle_file_parsing_moving_window( self, file_name: str, current_line: int, moving_window_size: int, moving_window: list, @@ -182,7 +188,7 @@ class ReturnValueParser(FileParser): ): """Parse for returnvalues using a moving window""" interface_id_match = re.search( - rf"{CLASS_ID_NAMESPACE}::([a-zA-Z_0-9]*)", moving_window[self._moving_window_center_idx] + rf'{CLASS_ID_NAMESPACE}::([a-zA-Z_0-9]*)', moving_window[self._moving_window_center_idx] ) if interface_id_match: @@ -202,22 +208,36 @@ class ReturnValueParser(FileParser): moving_window=moving_window, first_line=moving_window[self._moving_window_center_idx] ) + number_match = INVALID_IF_ID + # Try to match for a string using the new API first. Example: + # static const ReturnValue_t PACKET_TOO_LONG = + # HasReturnvaluesIF::makeReturnCode(CLASS_ID, 0); returnvalue_match = re.search( - r"^[\s]*static const(?:expr)? ReturnValue_t[\s]*([\w] *)[\s]*" + r"^[\s]*static const(?:expr)? ReturnValue_t[\s]*([\w]*)[\s]*" r"=[\s]*.*::[\w]*\(([\w]*),[\s]*([\d]*)\)", full_returnvalue_string ) if not returnvalue_match: + # Try to match for old API using MAE_RETURN_CODE macro returnvalue_match = re.search( r'^[\s]*static const(?:expr)? ReturnValue_t[\s]*([a-zA-Z_0-9]*)[\s]*=[\s]*' r'MAKE_RETURN_CODE[\s]*\([\s]*([\w]*)[\s]*\)', full_returnvalue_string ) + if returnvalue_match: + number_match = returnvalue_match.group(2) + else: + number_match = returnvalue_match.group(3) if returnvalue_match: description = self.__search_for_descrip_string(moving_window=moving_window) + if number_match == INVALID_IF_ID: + LOGGER.warning(f'Invalid number match detected for file {file_name}') + LOGGER.warning(f'Match groups:') + for group in returnvalue_match.groups(): + LOGGER.info(group) self.__handle_returnvalue_match( name_match=returnvalue_match.group(1), file_name=file_name, - number_match=returnvalue_match.group(2), description=description + number_match=number_match, description=description ) def __build_multi_line_returnvalue_string( @@ -256,17 +276,27 @@ class ReturnValueParser(FileParser): self.last_lines[1] = self.last_lines[0] self.last_lines[0] = newline - def __handle_interfaceid_match(self, interface_id_match, file_name: str): - if DEBUG_INTERFACE_ID_COMPARISON: - print(f"Interface ID {interface_id_match.group(1)} found in {file_name}") - self.current_interface_id_entries["ID"] = \ - self.interfaces[interface_id_match.group(1)][0] + def __handle_interfaceid_match(self, interface_id_match, file_name: str) -> bool: + """Handle a match of an interface ID definition in the code. + Returns whether the interface ID was found successfully in the IF ID header files + """ + if self.get_verbosity() == VerbosityLevels.DEBUG: + LOGGER.info(f'Interface ID {interface_id_match.group(1)} found in {file_name}') + if_id_entry = self.interfaces.get(interface_id_match.group(1)) + if if_id_entry is not None: + self.current_interface_id_entries["ID"] = if_id_entry[0] + else: + LOGGER.warning( + f'Interface ID {interface_id_match.group(1)} not found in IF ID dictionary' + ) + return False self.current_interface_id_entries["Name"] = \ self.interfaces[interface_id_match.group(1)][1] self.current_interface_id_entries["FullName"] = interface_id_match.group(1) - if DEBUG_INTERFACE_ID_COMPARISON: + if self.get_verbosity() == VerbosityLevels.DEBUG: current_id = self.current_interface_id_entries["ID"] - print(f"Current ID: {current_id}") + LOGGER.info(f'Current ID: {current_id}') + return True def __handle_returnvalue_match( self, name_match: str, number_match: str, file_name: str, description: str @@ -312,7 +342,7 @@ class ReturnValueParser(FileParser): my_str = first_part + '_' + self.convert(second_part) if len(my_str) > max_string_len: if print_truncated_entries: - print("Warning: Entry " + my_str + " too long. Will truncate.") + LOGGER.warning(f'Entry {my_str} too long. Will truncate.') my_str = my_str[0:max_string_len] else: # print("Entry: " + myStr + " is all right.") @@ -342,6 +372,6 @@ def return_number_from_string(a_string): return int(a_string, 16) if a_string.isdigit(): return int(a_string) - print('Error: Illegal number representation: ' + a_string) + LOGGER.warning(f'Illegal number representation: {a_string}') return 0