Commit 69778e10 authored by Greenwood, Scott's avatar Greenwood, Scott
Browse files

fixed issue with with default parsing and added flag to control inclusion of...

fixed issue with with default parsing and added flag to control inclusion of redeclare for default classes
parent eec09236
Loading
Loading
Loading
Loading
+23 −9
Original line number Diff line number Diff line
@@ -54,7 +54,8 @@ def sources_line(data, project_path, base_path, model_class_path, key_path, unif
    model_path = pathlib.Path(*model_path_list)
    
    # Find the default by searching for "redeclare replaceable Sources.* sources"
    default_source_class = parse_files.extract_default_class_from_model(model_path.as_posix(), 'Sources', 'sources')[0]
    default_source_class = parse_files.extract_default_class_from_model(model_path.as_posix(), 'Sources', 'sources')
    default_source_class = default_source_class if default_source_class == [] else default_source_class[0]
    
    # If 'SourceClass' is not in in the input file and is not the default, redeclare
    if 'SourceClass' in data.keys() and default_source_class != data['SourceClass']:
@@ -106,7 +107,7 @@ def sources_line(data, project_path, base_path, model_class_path, key_path, unif
    line += f'sources({temp if temp else ""})\n'
    return line

def create_nested_lines(data, project_path, base_path, uniform=[True,True], lines=None, is_top_system=True, key_path=None, level=0, last_modelClass=None):
def create_nested_lines(data, project_path, base_path, uniform=[True,True], lines=None, is_top_system=True, key_path=None, level=0, last_modelClass=None, force_redeclare=True):

    """
    Creates a list of lines representing the structure of the Modelica model.
@@ -114,10 +115,14 @@ def create_nested_lines(data, project_path, base_path, uniform=[True,True], line
    Args:
        data (dict): The input data dictionary.
        project_path (str): Path to the Modelica project folder.
        unifrom (list[2] bool): controls if structure [0] and sources [1] should be assumed uniform or individually
        lines (list, optional): An existing list of lines to append to. Defaults to None.
        is_top_system (bool, optional): Whether the current system is the top-level system. Defaults to True.
        structure_path (str, optional): The path to the structure template file.
        key_path (str) is the dotted path to the current point in hierarchy
        key_path (str): the dotted path to the current point in hierarchy
        level (int): the level into the hierarchy
        last_modelClass (string): the parent model class
        force_redeclare (bool): adds redeclare statement to file even when child class remains unchanged from the default value
    Returns:
        list: A list of lines representing the structure of the Modelica model.
    """
@@ -136,15 +141,22 @@ def create_nested_lines(data, project_path, base_path, uniform=[True,True], line
    model_instance_name = data['InstanceName']
    if is_top_system or'ModelClass' in data.keys():
        model_class_path = '.'.join([base_path, 'Models', data['ModelClass']])
        lines.append(f'redeclare {model_class_path} {model_instance_name}(')
    else:
        # If not specified in JSON, find default class from parent model (doesn't require redeclare b)
        temp_path = pathlib.Path(project_path).parts[:-1]
        model_path_list = list(temp_path) + base_path.split('.')[0:-2] + ['Models'] + [last_modelClass + '.mo']
        model_path = pathlib.Path(*model_path_list)
        data['ModelClass'] = parse_files.extract_default_class_from_model(model_path.as_posix(), 'Models', model_instance_name, include_redeclare=False)[0]
        default_class = parse_files.extract_default_class_from_model(model_path.as_posix(), 'Models', model_instance_name)
        data['ModelClass'] = default_class if default_class == [] else default_class[0]
        model_class_path = '.'.join([base_path, 'Models', data['ModelClass']])
        
    # Append line
        if force_redeclare:
            lines.append(f'redeclare {model_class_path} {model_instance_name}(')
        else:
            lines.append(f'{model_instance_name}(')


    
    # Current system changes
    ## Structure
@@ -156,7 +168,7 @@ def create_nested_lines(data, project_path, base_path, uniform=[True,True], line
    # Next system changes
    for sub_dict in data['Systems']:
        if sub_dict:  # Terminate if dictionary is empty
            lines = create_nested_lines(sub_dict, project_path, base_path, uniform, lines, False, key_path, level+1, data['ModelClass'])
            lines = create_nested_lines(sub_dict, project_path, base_path, uniform, lines, False, key_path, level+1, data['ModelClass'], force_redeclare)
    lines.append(')')

    return lines
@@ -187,7 +199,7 @@ def create_model_file(content, parent_class, output_path):
            mo_file.write(f'{var}\n')
        mo_file.write(f'end {temp_path.stem};')
        
def main(json_file_path, project_path, base_path, parent_class, output_path, structure_path, uniform=[False, False]):
def main(json_file_path, project_path, base_path, parent_class, output_path, structure_path, uniform=[False, False], force_redeclare=True):
    """
    Main function to create a Modelica model file based on the given input parameters.

@@ -197,6 +209,8 @@ def main(json_file_path, project_path, base_path, parent_class, output_path, str
        parent_class (str): The parent class to extend.
        output_path (str or pathlib.Path): The path to the output Modelica file.
        structure_path (str, optional): The path to the structure template file (contains the common structural parameters).
        unifrom (list[2] bool): controls if structure [0] and sources [1] should be assumed uniform or individually
        force_redeclare (bool): adds redeclare statement to file even when child class remains unchanged from the default value
    """
    data_orig = helper_functions.read_json(json_file_path)
    
@@ -207,7 +221,7 @@ def main(json_file_path, project_path, base_path, parent_class, output_path, str
    nested_structure_utils.expand_data(data, {item[2]: item[3] for item in default_structure_parameters})

    
    lines = create_nested_lines(data, project_path, base_path, uniform)
    lines = create_nested_lines(data, project_path, base_path, uniform, force_redeclare=force_redeclare)
    content = ','.join(lines).replace(',)', ')').replace('(,', '(')
    create_model_file(content, parent_class, output_path)
    return data
+4 −1
Original line number Diff line number Diff line
@@ -83,13 +83,16 @@ class ModelicaMethods(LanguageMethod):
                uniform = kwargs.pop('uniform', None)
                uniform = [True, True] if uniform is None or not uniform else uniform
                
                force_redeclare = kwargs.pop('force_redeclare', True)
                
                create_model_nested.main(self.parent.input_specification,
                                                  self.parent.project_path,
                                                  pathlib.Path(self.parent.project_path).name,
                                                  parent_class,
                                                  self.parent.model_path,
                                                  structure_path,
                                                  uniform)
                                                  uniform,
                                                  force_redeclare)
            #TODO: Add new architecture methods here
        except FileNotFoundError as e:
            raise RuntimeError(f"File not found during model creation: {e}")
+13 −42
Original line number Diff line number Diff line
@@ -75,59 +75,30 @@ def get_variable_by_type(file_path, dtype='parameter'):
    parameters = extract_variable(input_string, dtype)
    return parameters

def extract_default_class_from_model(file_path, folder='Sources', instance='sources', include_redeclare=True, include_replaceable = True):
def extract_default_class_from_model(file_path, folder='Sources', instance='sources', ignore_prefix=False):
    """
    Extracts the default class redeclaration for a given model file.
    Extracts class declarations matching specified patterns in a model file.

    Parameters:
    file_path (str): Path to the file to read.
    folder (str): Name of the folder (e.g., 'Sources', 'Models',...).
    instance (str): Name of the instance (e.g., 'sources').
    folder (str): Name of the folder or category to search within (e.g., 'Sources', 'Models').
    instance (str): Name of the instance to match (e.g., 'sources').
    ignore_prefix (bool): If True, allows matching classes even if 'redeclare' and 'replaceable' keywords are absent.

    Returns:
    list: A list of matches found for redeclared replaceable classes.
    """
    
    # prefixes = []
    
    # if include_redeclare:
    #     prefixes.append('redeclare')
    #     pattern = r'redeclare\s+replaceable\s+.*\{}.(\w+)\\s+{}'.format(prefixes, folder, instance)
            
    # if include_replaceable:
    #     prefixes.append('replaceable')
    list: A list of tuples where each tuple contains matches found for the specified classes.
    
    # # Combine to string ignoring all white space between
    # prefixes = r'\s+'.join(prefixes)
    
    # # # Define the regex pattern
    # pattern = r'{}\s+.*\{}.(\w+)\\s+{}'.format(prefixes, folder, instance)
    TODO: Could add option for enforcing redeclare or r
    """

    if include_redeclare and include_replaceable:
        pattern = r'\bredeclare\b\s+\breplaceable\b\s+.*\b{}\b.(\w+)\s+\b{}\b'.format(folder, instance)
    elif include_redeclare:
        pattern = r'redeclare\s+.*\\b{}\b.(\w+)\s+\b{}\b'.format(folder, instance)
    elif include_replaceable:
        pattern = r'replaceable\s+.*\b{}\b.(\w+)\s+\b{}\b'.format(folder, instance)
    if ignore_prefix:
        pattern = r'(?:\b(redeclare|replaceable)\b\s+)?\b{}\b\.(\w+)\s+\b{}\b'.format(folder, instance)
    else:
        pattern = r'\s+.*\\b{}\b.(\w+)\s+\b{}\b'.format(folder, instance)
    
        pattern = r'\b(?:redeclare|replaceable)\b\s+.*\b{}\b.(\w+)\s+\b{}\b'.format(folder, instance)

    with open(file_path, 'r') as file:
        content = file.read()
        # lines = file.readlines()

    # pattern = r'\b(?:replaceable|redeclare)\b.*\{folder}.(\w+)\s+{}'.format(folder, instance)
    
    # # Test the pattern on each line
    # matches = []
    # for line in lines:
    #     match = re.search(pattern, line)
    #     if match:
    #         matches.append(match.group(1))
    #     # else:
    #     #     print("No match found.")
    # return matches

    matches = re.findall(pattern, content)
    return matches