示例#1
0
    def edit_connect(self, port_a, port_b, new_port_a=None, new_port_b=None):
        """edit_connect finds all connect clauses that match the pattern
        connect(<port_a>, <port_b>), in that order. If a port is an asterisk, '*',
        then it matches any identifier.

        :param port_a: string, identifier for first port; an asterisk matches all
        :param port_b: string, identifier for second port; an asterisk matches all
        :param new_port_a: string | None, replacement for port a; if None no changes are made
        :param new_port_b: string | None, replacement for port b; if None no changes are made
        """
        # verify the paramaters are sensible
        if (port_a == '*'
                and new_port_a is not None) or (port_b == '*'
                                                and new_port_b is not None):
            raise Exception(
                'Invalid to have a port match a wildcard and replace it (might result in duplicate clauses)'
            )

        # make up to two transformations (one for each replacement)
        if new_port_a is not None:
            selector = (ConnectClauseSelector(port_a, port_b).chain(
                NthChildSelector(2)))
            self.add(
                SimpleTransformation(selector, Edit.make_replace(new_port_a)))

        if new_port_b is not None:
            selector = (ConnectClauseSelector(port_a, port_b).chain(
                NthChildSelector(4)))
            self.add(
                SimpleTransformation(selector, Edit.make_replace(new_port_b)))
示例#2
0
    def test_make_insert_before(self):
        # Setup
        insert = Edit.make_insert('Dog', insert_after=False)

        # Act
        edit = insert({'start': 0, 'stop': 2})
        result = Edit.apply_edits([edit], self.data)

        # Assert
        self.assertEqual('DogCatBat123', result)
示例#3
0
    def test_make_replace(self):
        # Setup
        replace = Edit.make_replace('Dog')

        # Act
        edit = replace({'start': 0, 'stop': 2})
        result = Edit.apply_edits([edit], self.data)

        # Assert
        self.assertEqual('DogBat123', result)
示例#4
0
    def set_name(self, name):
        """sets the model's name

        :param name: string
        """
        selector = ModelIdentifierSelector()
        self.add(SimpleTransformation(selector, Edit.make_replace(name)))
示例#5
0
    def build_edits(self, tree, parser):
        # try to find the model annotation
        model_annotation_xpath = 'stored_definition/class_definition/class_specifier/long_class_specifier/composition/model_annotation'
        model_annotation_node = XPath.XPath.findAll(tree,
                                                    model_annotation_xpath,
                                                    parser)
        if not model_annotation_node:
            # insert the model annotation along with the modifications
            selector = (EquationSectionSelector().chain(
                NthChildSelector(-1)).assert_count(
                    1, 'Failed to find end of the equation section'))

            edit = Edit.make_insert(
                f'\n{config.INDENTATION}annotation({build_modifications(self.modifications, indented=False)});'
            )
            return SimpleTransformation(selector,
                                        edit).build_edits(tree, parser)

        # model annotation exists, recursively update or insert the modifications
        model_annotation_node = model_annotation_node[0]
        return make_edits_for_modifications(
            model_annotation_node.annotation().class_modification(),
            self.modifications,
            parser,
            indented=config.INDENT_INSERTED_ANNOTATION_ARGS,
        )
示例#6
0
    def remove_connect(self, port_a, port_b):
        """remove_connect finds and removes the connect clause that matches

        :param port_a: string, first port identifier; an asterisk matches all
        :param port_b: string, second port identifier; an asterisk matches all
        """
        # select the parent of the component to also select the semicolon and comments
        selector = (ConnectClauseSelector(port_a,
                                          port_b).chain(ParentSelector()))
        self.add(SimpleTransformation(selector, Edit.make_delete()))
示例#7
0
    def set_within_statement(self, within_string):
        """changes 'within <string>;' at the beginning of
        the file

        :param within_string: string, new value
        """
        selector = (WithinSelector().assert_count(
            1, 'A single within statement must already exist'))
        self.add(
            SimpleTransformation(
                selector, Edit.make_replace(f'within {within_string};')))
示例#8
0
    def transformation(self):
        """transformation creates the transformation required for inserting the
        built for loop

        :return: Transformation
        """
        # select the last child of the equation section and insert after it
        selector = (EquationSectionSelector().chain(
            NthChildSelector(-1)).assert_count(
                1, 'Failed to find end of the equation section'))
        edit = Edit.make_insert(self.build(), insert_after=True)
        return SimpleTransformation(selector, edit)
示例#9
0
    def remove_component_argument(self, type_, identifier, argument_name):
        """Remove the argument from a component

        :param type_: string, type of the component
        :param identifier: string, component identifier
        :param argument_name: string, name of the argument that will be removed
        """
        if type_ is None and identifier is None:
            raise Exception('At least one of the parameters must not be None')

        selector = (ComponentDeclarationSelector(type_, identifier).chain(
            ComponentArgumentSelector(argument_name)))

        self.add(SimpleTransformation(selector, Edit.make_delete()))
示例#10
0
    def overwrite_component_redeclaration(self, type_, identifier,
                                          new_declaration):
        """
        Overwrite the component redeclaration with a new string

        :param type_: string, type of the component
        :param identifier: string, component identifier
        :param new_declaration: string, new component redeclaration string. It is the entire string, i.e., argument=value
        """
        selector = (ComponentDeclarationSelector(type_, identifier).chain(
            ComponentRedeclarationSelector()))

        self.add(
            SimpleTransformation(selector,
                                 Edit.make_replace(f'{new_declaration}')))
示例#11
0
    def rename_component_argument(self, type_, identifier, old_argument_name,
                                  new_argument_name):
        """Rename the argument name of a component

        :param type_: string, type of the component
        :param identifier: string, component identifier
        :param old_argument_name: string, name of the argument that will be replaced
        :param new_argument_name: string, name of the new argument name
        """
        selector = (ComponentDeclarationSelector(type_, identifier).chain(
            ComponentModificationNameSelector(old_argument_name)))

        self.add(
            SimpleTransformation(selector,
                                 Edit.make_replace(f'{new_argument_name}')))
示例#12
0
    def execute(self):
        """execute applies transformations to a file and returns the result as a string

        :return: string, transformed source
        """
        all_edits = []
        # apply selectors and build edits
        for transformation in self._transformations:
            all_edits += transformation.build_edits(self._tree, self._parser)

        # apply the edits
        # Reading with newline='' lets us retain the original newline characters
        # allowing us to handle files made on Windows with \r\n
        with open(self._source, 'rt', newline='') as f:
            return Edit.apply_edits(all_edits, f.read())
示例#13
0
    def remove_component(self, type_=None, identifier=None):
        """remove_component removes a component declaration.
        Note that if the component is part of a list of declarations, e.g.
        TypeName IdentifierA, IdentifierB, IdentifierC;
        then _all_ declarations are removed.

        :param type_: string, optional, type in the declaration
        :param identifier: string, optional, identifier in the declaration
        """
        if type_ is None and identifier is None:
            raise Exception('At least one of the parameters must not be None')

        selector = (
            ComponentDeclarationSelector(type_, identifier).chain(
                ParentSelector())  # component_list
            .chain(ParentSelector())  # component_clause
            .chain(ParentSelector()))  # element

        self.add(SimpleTransformation(selector, Edit.make_delete()))
示例#14
0
    def update_component_modification(self,
                                      type_,
                                      identifier,
                                      modification_name,
                                      new_value,
                                      if_value=None):
        """update_component_modification changes the value of an _existing_ component
        modification value. ie this won't work if the argument isn't already used

        :param type_: string, component type
        :param identifier: string, component identifier
        :param modification_name: string, modification to update
        :param new_value: string, new modification value
        :param if_value: string, if provided it will only update the value if the existing value matches this
        """
        selector = (ComponentDeclarationSelector(type_, identifier).chain(
            ComponentModificationValueSelector(modification_name,
                                               modification_value=if_value)))

        self.add(SimpleTransformation(selector, Edit.make_replace(new_value)))
示例#15
0
    def transformation(self):
        """transformation creates the transformation required for inserting the
        built component

        :return: Transformation
        """
        if self._insert_index == 0:
            selector = (ElementListSelector().chain(NthChildSelector(0)))
            insert_after = False
        elif self._insert_index < 0:
            # insert after the last child
            selector = (ElementListSelector().chain(NthChildSelector(-1)))
            insert_after = True
        else:
            selector = (ElementListSelector().chain(
                NthChildSelector(self._insert_index)))
            insert_after = True

        edit = Edit.make_insert(self.build(), insert_after=insert_after)
        return SimpleTransformation(selector, edit)
示例#16
0
def make_edits_for_modifications(class_modification_node,
                                 modifications,
                                 parser,
                                 depth=1,
                                 indented=False):
    """Constructs a list of edits required to update the node with the
    provided modifications.

    :param class_modification_node: modelicaParser.Class_modificationContext
    :param modifications: dict
    :param parser: antlr4.Parser
    :param depth: int, current modification depth, used for determining code indentation
    :param indent: bool, if true each inserted modification will be indented on new line
    """
    requested_modifications = deepcopy(modifications)
    overwrite_modifications = requested_modifications.pop(
        'OVERWRITE_MODIFICATIONS', False)
    if overwrite_modifications:
        # don't care about selectively updating existing values
        # just overwrite any existing modifications
        new_modifications_string = build_modifications(requested_modifications,
                                                       depth=depth,
                                                       indented=indented)
        edit = Edit.make_replace(new_modifications_string)
        # replace the entire argument_list with our new modifications
        return [edit(class_modification_node.argument_list())]

    all_edits = []
    element_modification_xpath = 'class_modification/argument_list/argument/element_modification_or_replaceable/element_modification'
    element_modification_nodes = XPath.XPath.findAll(
        class_modification_node, element_modification_xpath, parser)

    # iterate through the existing element modifications
    for element_modification_node in element_modification_nodes:
        # check if there's a request to update this modification
        element_modification_name = element_modification_node.name().getText()
        if element_modification_name in requested_modifications:
            # found a modification to update
            requested_modification_value = requested_modifications.pop(
                element_modification_name)
            if isinstance(requested_modification_value, dict):
                # recursively make edits for this modification
                next_class_modification_node = element_modification_node.modification(
                ).class_modification()
                all_edits += make_edits_for_modifications(
                    next_class_modification_node,
                    requested_modification_value,
                    parser,
                    depth=depth + 1,
                    indented=indented)
            else:
                edit = Edit.make_replace(f'={requested_modification_value}')
                # replace the modification node with our value
                all_edits.append(edit(
                    element_modification_node.modification()))

    # remaining modifications will need to be inserted (matched modification were removed from the dict)
    if requested_modifications:
        new_modifications_string = build_modifications(requested_modifications,
                                                       depth=depth,
                                                       indented=indented)
        edit = Edit.make_insert(', ' + new_modifications_string,
                                insert_after=True)
        all_edits.append(edit(class_modification_node.argument_list()))

    return all_edits