예제 #1
0
    def deep_find_match_Name(self, ins_node, std_node, check_meta=True):
        name_id = ins_node.astNode.id
        match = _name_regex(name_id)
        mapping = AstMap()
        matched = False
        meta_matched = self.metas_match(ins_node, std_node, check_meta)
        if match[_VAR] and meta_matched:  # if variable
            # This if body is probably unnecessary.
            if type(std_node.astNode).__name__ == "Name":
                return self.deep_find_match_generic(ins_node, std_node,
                                                    check_meta)
        # could else return False, but shallow_match_generic should do this as well
        elif match[_EXP]:  # and meta_matched:  # if expression
            # terminate recursion, the whole subtree should match since expression nodes match to anything
            mapping.add_exp_to_sym_table(ins_node, std_node)
            matched = True
        elif match[_WILD] and meta_matched:  # if wild card, don't care
            # terminate the recursion, the whole subtree should match since wild cards match to anything
            matched = True

        if matched:
            mapping.add_node_pairing(ins_node, std_node)
            return [mapping]
        # else
        return self.deep_find_match_generic(ins_node, std_node, check_meta)
예제 #2
0
    def deep_find_match_Expr(self, ins_node, std_node, check_meta=True):
        """
        An Expression node (not to be confused with expressions denoted by the instructor nodes in Name ast nodes)
        checks whether it should be generic, or not
        Args:
            ins_node: Instructor ast to find in the student ast
            std_node: Student AST to search for the instructor ast in
            check_meta: flag to check whether the fields of the instructor node and the student node should match

        Returns:
            AstMap: a mapping between the instructor and student asts, or False if such a mapping doesn't exist
        """
        # if check_meta and ins_node.field != std_node.field:
        if not self.metas_match(ins_node, std_node, check_meta):
            return []
        mapping = AstMap()
        value = ins_node.value
        ast_type = type(value.astNode).__name__
        if ast_type == "Name":
            name_id = value.astNode.id
            exp_match = re.compile('^__.*__$')  # /regex
            wild_card = re.compile('^___$')  # /regex
            matched = False
            meta_matched = self.metas_match(ins_node, std_node, check_meta)
            if exp_match.match(name_id):  # and meta_matched:  # if expression
                # terminate recursion, the whole subtree should match since expression nodes match to anything
                mapping.add_exp_to_sym_table(value, std_node)
                matched = True
            elif wild_card.match(name_id) and meta_matched:  # if wild card, don't care
                # terminate the recursion, the whole subtree should match since wild cards match to anything
                matched = True
            if matched:
                mapping.add_node_pairing(ins_node, std_node)
                return [mapping]
        return self.deep_find_match_generic(ins_node, std_node, check_meta)
예제 #3
0
    def shallow_symbol_handler(self,
                               ins_node,
                               std_node,
                               id_val,
                               check_meta=True):
        """
        TODO: Make this handle the func field to handle functions
        Matches ins_node to std_node for different cases of encountering a name node in ins_node
            case 1: _var_ matches if std_node is a name node and automatically returns a mapping and symbol table
            case 2: __exp__ matches to any subtree and automatically returns a mapping and symbol table
            case 3: ___ matches to any subtree and automatically returns a mapping
            case 4: matches only if the exact names are the same (falls through to shallow_match_generic)
        Args:
            ins_node:
            std_node:
            id_val:
            check_meta:

        Returns:
            list of AstMap: a mapping of ins_node to std_node and possibly a symbol_table, or False if it doesn't match
        """
        name_id = ins_node.astNode.__getattribute__(id_val)
        match = _name_regex(name_id)
        mapping = AstMap()
        matched = False
        # TODO: add functionality to add function references to func_table?
        meta_matched = self.metas_match(ins_node, std_node, check_meta)
        if match[_VAR] and meta_matched:  # variable
            if type(std_node.astNode).__name__ == "Name" or id_val == "attr":
                if id_val == "attr":
                    std_node.astNode.id = std_node.astNode.attr
                if std_node.field == "func" and ins_node.field != "none":
                    # TODO: This 'ins_node.field != "none"' code is for an obscure edge case where the instructor code
                    # is only _var_
                    mapping.add_func_to_sym_table(ins_node, std_node)
                else:
                    mapping.add_var_to_sym_table(
                        ins_node, std_node)  # TODO: Capture result?
                matched = True
        # could else return False, but shallow_match_generic should do this as well
        elif match[
                _EXP] and meta_matched:  # expression TODO: In theory this won't run?
            mapping.add_exp_to_sym_table(ins_node, std_node)
            matched = True
        elif match[
                _WILD] and meta_matched:  # don't care TODO: In theory this won't run?
            matched = True

        if matched:
            mapping.add_node_pairing(ins_node, std_node)
            return [mapping]
        # else
        return self.shallow_match_generic(ins_node, std_node, check_meta)
예제 #4
0
    def shallow_symbol_handler(self, ins_node, std_node, id_val, check_meta=True):
        """
        TODO: Make this handle the func field to handle functions
        Matches ins_node to std_node for different cases of encountering a name node in ins_node
            case 1: _var_ matches if std_node is a name node and automatically returns a mapping and symbol table
            case 2: __exp__ matches to any subtree and automatically returns a mapping and symbol table
            case 3: ___ matches to any subtree and automatically returns a mapping
            case 4: matches only if the exact names are the same (falls through to shallow_match_generic)
        Args:
            ins_node:
            std_node:
            id_val:
            check_meta:

        Returns:
            list of AstMap: a mapping of ins_node to std_node and possibly a symbol_table, or False if it doesn't match
        """
        name_id = ins_node.astNode.__getattribute__(id_val)
        match = _name_regex(name_id)
        mapping = AstMap()
        matched = False
        # TODO: add functionality to add function references to func_table?
        meta_matched = self.metas_match(ins_node, std_node, check_meta)
        if match[_VAR] and meta_matched:  # variable
            if type(std_node.astNode).__name__ == "Name" or id_val in ["attr", "arg"]:
                if id_val in ["attr", "arg"]:
                    std_node.astNode._id = std_node.astNode.__getattribute__(id_val)
                if std_node.field == "func" and ins_node.field != _NONE_FIELD:
                    # TODO: This 'ins_node.field != _NONE_FIELD' code is for an obscure edge case where the
                    #  instructor code is only _var_
                    std_node.astNode._id = std_node.astNode.__getattribute__(id_val)
                    mapping.add_func_to_sym_table(ins_node, std_node)
                else:
                    std_node.astNode._id = std_node.astNode.__getattribute__(id_val)
                    mapping.add_var_to_sym_table(ins_node, std_node)  # TODO: Capture result?
                matched = True
        # could else return False, but shallow_match_generic should do this as well
        elif match[_EXP] and meta_matched:
            mapping.add_exp_to_sym_table(ins_node, std_node)
            matched = True
        elif match[_WILD] and meta_matched:
            matched = True

        if matched:
            mapping.add_node_pairing(ins_node, std_node)
            return [mapping]
        # else
        return self.shallow_match_main(ins_node, std_node, check_meta=check_meta, ignores=["ctx"])
예제 #5
0
    def shallow_match_Module(self, ins_node, std_node, check_meta=True):
        """
        Flexibly matches a module node to a module or a body
        Args:
            ins_node:
            std_node:
            check_meta:

        Returns:
            a mapping of ins_node to std_node, or False if doesn't match
        """
        if type(std_node.astNode).__name__ == "Module" or std_node.field == "body":
            mapping = AstMap()
            mapping.add_node_pairing(ins_node, std_node)
            return [mapping]
        return []
예제 #6
0
    def shallow_match_Module(self, ins_node, std_node, check_meta=True):
        """
        Flexibly matches a module node to a module or a body
        Args:
            ins_node:
            std_node:
            check_meta:

        Returns:
            a mapping of ins_node to std_node, or False if doesn't match
        """
        if type(std_node.astNode).__name__ == "Module" or std_node.field == "body":
            mapping = AstMap()
            mapping.add_node_pairing(ins_node, std_node)
            return [mapping]
        return []
예제 #7
0
    def deep_find_match_Name(self,
                             ins_node,
                             std_node,
                             check_meta=True,
                             use_previous=None):
        """

        Args:
            ins_node:
            std_node:
            check_meta:
            use_previous:

        Returns:

        """
        name_id = ins_node.astNode.id
        match = _name_regex(name_id)
        mapping = AstMap()
        matched = False
        meta_matched = self.metas_match(ins_node, std_node, check_meta)
        if match[_VAR] and meta_matched:  # if variable
            if type(std_node.astNode).__name__ == "Name":
                return self.deep_find_match_generic(ins_node,
                                                    std_node,
                                                    check_meta=check_meta,
                                                    ignores=["ctx"],
                                                    use_previous=use_previous)
        # could else return False, but shallow_match_generic should do this as well
        elif match[_EXP] and meta_matched:  # and meta_matched:  # if expression
            # terminate recursion, the whole subtree should match since expression nodes match to anything
            mapping.merge_map_with(use_previous)
            mapping.add_exp_to_sym_table(ins_node, std_node)
            matched = True
        elif match[_WILD] and meta_matched:  # if wild card, don't care
            # terminate the recursion, the whole subtree should match since wild cards match to anything
            matched = True

        if matched:
            mapping.add_node_pairing(ins_node, std_node)
            return [mapping]
        # else
        return self.deep_find_match_generic(ins_node,
                                            std_node,
                                            check_meta=check_meta,
                                            ignores=["ctx"],
                                            use_previous=use_previous)
예제 #8
0
    def shallow_match_Pass(self, ins_node, std_node, check_meta=True):
        """
        An empty body should match to anything
        Args:
            ins_node: Instructor ast to find in the student ast
            std_node: Student AST to search for the instructor ast in
            check_meta: flag to check whether the fields of the instructor node and the student node should match

        Returns:
            list of AstMap: a mapping between the isntructor and student asts, or False if such a mapping doesn't exist
        """
        # if check_meta and ins_node.field != std_node.field:
        if not self.metas_match(ins_node, std_node, check_meta):
            return []
        mapping = AstMap()
        mapping.add_node_pairing(ins_node, std_node)
        return [mapping]
예제 #9
0
    def shallow_match_Pass(self, ins_node, std_node, check_meta=True):
        """
        An empty body should match to anything
        Args:
            ins_node: Instructor ast to find in the student ast
            std_node: Student AST to search for the instructor ast in
            check_meta: flag to check whether the fields of the instructor node and the student node should match

        Returns:
            list of AstMap: a mapping between the isntructor and student asts, or False if such a mapping doesn't exist
        """
        # if check_meta and ins_node.field != std_node.field:
        if not self.metas_match(ins_node, std_node, check_meta):
            return []
        mapping = AstMap()
        mapping.add_node_pairing(ins_node, std_node)
        return [mapping]
예제 #10
0
    def shallow_match_Expr(self, ins_node, std_node, check_meta=True):
        """
        An Expression node (not to be confused with expressions denoted by the instructor nodes in Name ast nodes)
        should match to anything
        Args:
            ins_node: Instructor ast to find in the student ast
            std_node: Instructor ast to find in the student ast
            check_meta: flag to check whether the fields of the instructor node and the student node should match

        Returns:
            a mapping between the instructor and student asts, or False if such a mapping doesn't exist
        """
        # if check_meta and ins_node.field != std_node.field:
        if not self.metas_match(ins_node, std_node, check_meta):
            return []
        mapping = AstMap()
        mapping.add_node_pairing(ins_node, std_node)
        return [mapping]
예제 #11
0
    def shallow_match_Expr(self, ins_node, std_node, check_meta=True):
        """
        An Expression node (not to be confused with expressions denoted by the instructor nodes in Name ast nodes)
        should match to anything
        Args:
            ins_node: Instructor ast to find in the student ast
            std_node: Instructor ast to find in the student ast
            check_meta: flag to check whether the fields of the instructor node and the student node should match

        Returns:
            a mapping between the instructor and student asts, or False if such a mapping doesn't exist
        """
        # if check_meta and ins_node.field != std_node.field:
        if not self.metas_match(ins_node, std_node, check_meta):
            return []
        mapping = AstMap()
        mapping.add_node_pairing(ins_node, std_node)
        return [mapping]
예제 #12
0
    def deep_find_match_Expr(self,
                             ins_node,
                             std_node,
                             check_meta=True,
                             use_previous=None):
        """
        An Expression node (not to be confused with expressions denoted by the instructor nodes in Name ast nodes)
        checks whether it should be generic, or not
        Args:
            ins_node: Instructor ast to find in the student ast
            std_node: Student AST to search for the instructor ast in
            check_meta: flag to check whether the fields of the instructor node and the student node should match
            use_previous: An AstMap from a previous matching run

        Returns:
            AstMap: a mapping between the instructor and student asts, or False if such a mapping doesn't exist
        """
        # if check_meta and ins_node.field != std_node.field:
        if not self.metas_match(ins_node, std_node, check_meta):
            return []
        mapping = AstMap() if use_previous is None else use_previous
        value = ins_node.value
        ast_type = type(value.astNode).__name__
        if ast_type == "Name":
            name_id = value.astNode.id
            exp_match = re.compile('^__.*__$')  # /regex
            wild_card = re.compile('^___$')  # /regex
            matched = False
            meta_matched = self.metas_match(ins_node, std_node, check_meta)
            if exp_match.match(
                    name_id
            ) and meta_matched:  # and meta_matched:  # if expression
                # terminate recursion, the whole subtree should match since expression nodes match to anything
                mapping.add_exp_to_sym_table(value, std_node)
                matched = True
            elif wild_card.match(
                    name_id) and meta_matched:  # if wild card, don't care
                # terminate the recursion, the whole subtree should match since wild cards match to anything
                matched = True
            if matched:
                mapping.add_node_pairing(ins_node, std_node)
                return [mapping]
        return self.deep_find_match_generic(ins_node, std_node, check_meta)
예제 #13
0
    def deep_find_match_Name(self, ins_node, std_node, check_meta=True):
        name_id = ins_node.astNode.id
        match = _name_regex(name_id)
        mapping = AstMap()
        matched = False
        meta_matched = self.metas_match(ins_node, std_node, check_meta)
        if match[_VAR] and meta_matched:  # if variable
            # This if body is probably unnecessary.
            if type(std_node.astNode).__name__ == "Name":
                return self.deep_find_match_generic(ins_node, std_node, check_meta=check_meta, ignores=["ctx"])
        # could else return False, but shallow_match_generic should do this as well
        elif match[_EXP]:  # and meta_matched:  # if expression
            # terminate recursion, the whole subtree should match since expression nodes match to anything
            mapping.add_exp_to_sym_table(ins_node, std_node)
            matched = True
        elif match[_WILD] and meta_matched:  # if wild card, don't care
            # terminate the recursion, the whole subtree should match since wild cards match to anything
            matched = True

        if matched:
            mapping.add_node_pairing(ins_node, std_node)
            return [mapping]
        # else
        return self.deep_find_match_generic(ins_node, std_node, check_meta=check_meta, ignores=["ctx"])
예제 #14
0
    def shallow_match_main(self, ins_node, std_node, check_meta=True, ignores=None):
        """
        Checks that all non astNode attributes are equal between ins_node and std_node
        Args:
            ins_node: Instructor ast root node
            std_node: Student AST root node
            check_meta: flag to check whether the fields of the instructor node and the student node should match
            ignores: a mapping between the instructor and student root nodes, or False if such a mapping doesn't exist

        Returns:

        """
        if ignores is None:
            ignores = []
        ignores.append("_id")  # special exception for symbols in lookup tables
        ins = ins_node.astNode
        std = std_node.astNode
        ins_field_list = list(ast.iter_fields(ins))
        std_field_list = list(ast.iter_fields(std))
        meta_matched = self.metas_match(ins_node, std_node, check_meta)
        is_match = len(ins_field_list) == len(std_field_list) and type(ins).__name__ == type(
            std).__name__ and meta_matched
        for insTup, stdTup in zip(ins_field_list, std_field_list):
            if not is_match:
                break

            ins_field = insTup[0]
            ins_value = insTup[1]
            std_field = stdTup[0]
            std_value = stdTup[1]

            if ins_value is None:
                continue

            ignore_field = ins_field in ignores

            is_match = (ins_field == std_field) or ignore_field

            if not isinstance(ins_value, list):
                ins_value = [ins_value]

            if not isinstance(std_value, list):
                std_value = [std_value]

            # is_match = len(ins_value) == len(std_value)# for stretchy matching this isn't True
            # Reference ast_node_visitor.js for the original behavior and keep note of it for the purposes of handling
            # the children noting the special case when the nodes of the array are actually parameters of the node
            # (e.g. a load function) instead of a child node
            if not ignore_field:
                for inssub_value, stdsub_value in zip(ins_value, std_value):
                    if not is_match:
                        break
                    # TODO: make this a smarter comparison, maybe handle dictionaries, f-strings, tuples, etc.
                    if is_primitive(inssub_value):
                        is_match = inssub_value == stdsub_value
        if is_match:
            mapping = AstMap()  # return MAPPING
            mapping.add_node_pairing(ins_node, std_node)
            return [mapping]
        else:
            return []
예제 #15
0
    def shallow_match_main(self, ins_node, std_node, check_meta=True, ignores=None):
        """
        Checks that all non astNode attributes are equal between ins_node and std_node
        Args:
            ins_node: Instructor ast root node
            std_node: Student AST root node
            check_meta: flag to check whether the fields of the instructor node and the student node should match
            ignores: a mapping between the instructor and student root nodes, or False if such a mapping doesn't exist

        Returns:

        """
        if ignores is None:
            ignores = []
        ignores.append("_id")  # special exception for symbols in lookup tables
        ins = ins_node.astNode
        std = std_node.astNode
        ins_field_list = list(ast.iter_fields(ins))
        std_field_list = list(ast.iter_fields(std))
        meta_matched = self.metas_match(ins_node, std_node, check_meta)
        is_match = len(ins_field_list) == len(std_field_list) and type(ins).__name__ == type(
            std).__name__ and meta_matched
        for insTup, stdTup in zip(ins_field_list, std_field_list):
            if not is_match:
                break

            ins_field = insTup[0]
            ins_value = insTup[1]
            std_field = stdTup[0]
            std_value = stdTup[1]

            if ins_value is None:
                continue

            ignore_field = ins_field in ignores

            is_match = (ins_field == std_field) or ignore_field

            if not isinstance(ins_value, list):
                ins_value = [ins_value]

            if not isinstance(std_value, list):
                std_value = [std_value]

            # is_match = len(ins_value) == len(std_value)# for stretchy matching this isn't True
            # Reference ast_node_visitor.js for the original behavior and keep note of it for the purposes of handling
            # the children noting the special case when the nodes of the array are actually parameters of the node
            # (e.g. a load function) instead of a child node
            if not ignore_field:
                for inssub_value, stdsub_value in zip(ins_value, std_value):
                    if not is_match:
                        break
                    # TODO: make this a smarter comparison, maybe handle dictionaries, f-strings, tuples, etc.
                    if is_primitive(inssub_value):
                        is_match = inssub_value == stdsub_value
        if is_match:
            mapping = AstMap()  # return MAPPING
            mapping.add_node_pairing(ins_node, std_node)
            return [mapping]
        else:
            return []