several bugfixes and improvements

This commit is contained in:
Robin Müller 2021-08-02 12:49:10 +02:00
parent 8e805d2408
commit 16280cc1df
No known key found for this signature in database
GPG Key ID: 71B58F8A3CDFA9AC
3 changed files with 70 additions and 29 deletions

View File

@ -1,37 +1,37 @@
""" """Generic File Parser class
@file file_list_parser.py
@brief Generic File Parser class
@details
Used by parse header files. Implemented as class in case header parser becomes more complex 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 os
import re import re
from typing import Union from typing import Union
from fsfwgen.core import get_console_logger
LOGGER = get_console_logger()
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
class FileListParser: 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. 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]): def __init__(self, directory_list_or_name: Union[str, list]):
self.directory_list = []
if isinstance(directory_list_or_name, str): 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): elif isinstance(directory_list_or_name, list):
self.directory_list = directory_list_or_name self.directory_list.extend(directory_list_or_name)
else: else:
print("Header Parser: Passed directory list is not a header name or list of " LOGGER.warning(
"header names") "Header Parser: Passed directory list is not a header name or list of header names"
)
self.header_files = [] self.header_files = []
def parse_header_files(self, search_recursively: bool = False, def parse_header_files(self, search_recursively: bool = False,
printout_string: str = "Parsing header files: ", printout_string: str = "Parsing header files: ",
print_current_dir: bool = False): 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 search_recursively:
:param printout_string: :param printout_string:
:param print_current_dir: :param print_current_dir:

View File

@ -17,6 +17,12 @@ from abc import abstractmethod
from typing import Dict, List from typing import Dict, List
class VerbosityLevels(enum.Enum):
REDUCED = 0,
REGULAR = 1,
DEBUG = 2
class FileParserModes(enum.Enum): class FileParserModes(enum.Enum):
REGULAR = enum.auto(), REGULAR = enum.auto(),
MOVING_WINDOW = enum.auto() MOVING_WINDOW = enum.auto()
@ -72,6 +78,9 @@ class FileParser:
def set_verbosity(self, verbose_level: int): def set_verbosity(self, verbose_level: int):
self._verbose_level = verbose_level self._verbose_level = verbose_level
def get_verbosity(self):
return self._verbose_level
def enable_moving_window_debugging(self, file_name: str): def enable_moving_window_debugging(self, file_name: str):
self.__debug_moving_window = True self.__debug_moving_window = True
self.__debug_moving_window_filename = file_name self.__debug_moving_window_filename = file_name
@ -201,6 +210,8 @@ class FileParser:
def _build_multi_line_string_generic( def _build_multi_line_string_generic(
self, first_line: str, moving_window: List[str] self, first_line: str, moving_window: List[str]
) -> 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() all_lines = first_line.rstrip()
end_found = False end_found = False
current_idx = self._moving_window_center_idx current_idx = self._moving_window_center_idx

View File

@ -2,19 +2,21 @@ import re
import sys import sys
from typing import List, Tuple 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.utility.printer import PrettyPrinter
from fsfwgen.core import get_console_logger
LOGGER = get_console_logger()
# Intermediate solution # Intermediate solution
MAX_STRING_LEN = 80 MAX_STRING_LEN = 80
PRINT_TRUNCATED_ENTRIES = False PRINT_TRUNCATED_ENTRIES = False
DEBUG_INTERFACE_ID_COMPARISON = False
DEBUG_FOR_FILE_NAME = False DEBUG_FOR_FILE_NAME = False
DEBUG_FILE_NAME = "RingBufferAnalyzer"
CLASS_ID_NAMESPACE = "CLASS_ID" CLASS_ID_NAMESPACE = "CLASS_ID"
DEFAULT_MOVING_WINDOWS_SIZE = 7 DEFAULT_MOVING_WINDOWS_SIZE = 7
INVALID_IF_ID = -1
class InterfaceParser(FileParser): class InterfaceParser(FileParser):
@ -26,6 +28,10 @@ class InterfaceParser(FileParser):
self.file_name_table = [] self.file_name_table = []
self.start_name_list = [] self.start_name_list = []
self.end_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( def _handle_file_parsing_moving_window(
self, file_name: str, current_line: int, moving_window_size: int, moving_window: list, 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""" """Parse for returnvalues using a moving window"""
interface_id_match = re.search( 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: if interface_id_match:
@ -202,22 +208,36 @@ class ReturnValueParser(FileParser):
moving_window=moving_window, moving_window=moving_window,
first_line=moving_window[self._moving_window_center_idx] 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( 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]*)\)", r"=[\s]*.*::[\w]*\(([\w]*),[\s]*([\d]*)\)",
full_returnvalue_string full_returnvalue_string
) )
if not returnvalue_match: if not returnvalue_match:
# Try to match for old API using MAE_RETURN_CODE macro
returnvalue_match = re.search( returnvalue_match = re.search(
r'^[\s]*static const(?:expr)? ReturnValue_t[\s]*([a-zA-Z_0-9]*)[\s]*=[\s]*' r'^[\s]*static const(?:expr)? ReturnValue_t[\s]*([a-zA-Z_0-9]*)[\s]*=[\s]*'
r'MAKE_RETURN_CODE[\s]*\([\s]*([\w]*)[\s]*\)', r'MAKE_RETURN_CODE[\s]*\([\s]*([\w]*)[\s]*\)',
full_returnvalue_string full_returnvalue_string
) )
if returnvalue_match:
number_match = returnvalue_match.group(2)
else:
number_match = returnvalue_match.group(3)
if returnvalue_match: if returnvalue_match:
description = self.__search_for_descrip_string(moving_window=moving_window) 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( self.__handle_returnvalue_match(
name_match=returnvalue_match.group(1), file_name=file_name, 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( def __build_multi_line_returnvalue_string(
@ -256,17 +276,27 @@ class ReturnValueParser(FileParser):
self.last_lines[1] = self.last_lines[0] self.last_lines[1] = self.last_lines[0]
self.last_lines[0] = newline self.last_lines[0] = newline
def __handle_interfaceid_match(self, interface_id_match, file_name: str): def __handle_interfaceid_match(self, interface_id_match, file_name: str) -> bool:
if DEBUG_INTERFACE_ID_COMPARISON: """Handle a match of an interface ID definition in the code.
print(f"Interface ID {interface_id_match.group(1)} found in {file_name}") Returns whether the interface ID was found successfully in the IF ID header files
self.current_interface_id_entries["ID"] = \ """
self.interfaces[interface_id_match.group(1)][0] 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.current_interface_id_entries["Name"] = \
self.interfaces[interface_id_match.group(1)][1] self.interfaces[interface_id_match.group(1)][1]
self.current_interface_id_entries["FullName"] = interface_id_match.group(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"] 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( def __handle_returnvalue_match(
self, name_match: str, number_match: str, file_name: str, description: str 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) my_str = first_part + '_' + self.convert(second_part)
if len(my_str) > max_string_len: if len(my_str) > max_string_len:
if print_truncated_entries: 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] my_str = my_str[0:max_string_len]
else: else:
# print("Entry: " + myStr + " is all right.") # print("Entry: " + myStr + " is all right.")
@ -342,6 +372,6 @@ def return_number_from_string(a_string):
return int(a_string, 16) return int(a_string, 16)
if a_string.isdigit(): if a_string.isdigit():
return int(a_string) return int(a_string)
print('Error: Illegal number representation: ' + a_string) LOGGER.warning(f'Illegal number representation: {a_string}')
return 0 return 0