示例#1
0
    def _get_import_priorities(self) -> 'ImportPriorities':
        if not self._import_priorities:
            import_priorities = ImportPriorities()
            import_priorities.import_priority[self] = ImportInfo(0, False)
            self._prioritize_imports(set(), import_priorities, 1, False)
            self._import_priorities = import_priorities

        # make a copy so the caller doesn't mess these up
        return self._import_priorities.copy()
示例#2
0
    def _prioritize_imports(self, processed_set: Set['CdmDocumentDefinition'], import_priorities: 'ImportPriorities', sequence: int, \
                            skip_monikered: bool) -> int:
        # goal is to make a map from the reverse order of imports (breadth first) to the first (aka last) sequence number in that list.
        # This gives the semantic that the 'last/shallowest' definition for a duplicate symbol wins,
        # the lower in this list a document shows up, the higher priority its definitions are for resolving conflicts.
        # for 'moniker' imports, keep track of the 'last/shallowest' use of each moniker tag.

        # maps document to priority.
        priority_map = import_priorities.import_priority  # type: Dict[CdmDocumentDefinition, ImportInfo]

        # maps moniker to document.
        moniker_map = import_priorities.moniker_priority_map  # type: Dict[str, CdmDocumentDefinition]

        # if already in list, don't do this again
        if self in processed_set:
            # if the first document in the priority map is this then the document was the starting point of the recursion.
            # and if this document is present in the processedSet we know that there is a circular list of imports.
            if self in priority_map and priority_map[self].priority == 0:
                import_priorities.has_circular_import = True
            return sequence

        processed_set.add(self)

        if self.imports:
            # reverse order.
            # first add the imports done at this level only.
            # reverse the list
            reversed_imports = self.imports[::-1]  # type: List[CdmImport]
            moniker_imports = []  # type: List[CdmDocumentDefinition]

            for imp in reversed_imports:
                imp_doc = imp._document  # type: CdmDocumentDefinition

                # moniker imports will be added to the end of the priority list later.
                if imp_doc:
                    if not imp.moniker and imp_doc not in priority_map:
                        # add doc
                        priority_map[imp_doc] = ImportInfo(sequence, False)
                        sequence += 1
                    else:
                        moniker_imports.append(imp_doc)
                else:
                    logger.warning(
                        self.ctx, self._TAG,
                        CdmDocumentDefinition._prioritize_imports.__name__,
                        self.at_corpus_path,
                        CdmLogCode.WARN_DOC_IMPORT_NOT_LOADED, imp.corpus_path)

            # now add the imports of the imports.
            for imp in reversed_imports:
                imp_doc = imp._document  # type: CdmDocumentDefinition
                is_moniker = bool(imp.moniker)

                if not imp_doc:
                    logger.warning(
                        self.ctx, self._TAG,
                        CdmDocumentDefinition._prioritize_imports.__name__,
                        self.at_corpus_path,
                        CdmLogCode.WARN_DOC_IMPORT_NOT_LOADED, imp.corpus_path)

                # if the document has circular imports its order on the impDoc.ImportPriorities list is not correct
                # since the document itself will always be the first one on the list.
                if imp_doc and imp_doc._import_priorities and not imp_doc._import_priorities.has_circular_import:
                    # lucky, already done so avoid recursion and copy
                    imp_pri_sub = imp_doc._get_import_priorities()
                    imp_pri_sub.import_priority.pop(
                        imp_doc)  # because already added above
                    imports = list(imp_pri_sub.import_priority.keys())
                    imports.sort(key=lambda doc: imp_pri_sub.import_priority[
                        doc].priority)
                    for key in imports:
                        # if the document is imported with moniker in another document do not include it in the priority list of this one.
                        # moniker imports are only added to the priority list of the document that directly imports them.
                        if key not in priority_map and not imp_pri_sub.import_priority[
                                key].is_moniker:
                            # add doc
                            priority_map[key] = ImportInfo(sequence, False)
                            sequence += 1

                    # if the import is not monikered then merge its monikerMap to this one.
                    if not is_moniker:
                        for key, value in imp_pri_sub.moniker_priority_map.items(
                        ):
                            moniker_map[key] = value
                elif imp_doc:
                    # skip the monikered imports from here if this is a monikered import itself and we are only collecting the dependencies
                    sequence = imp_doc._prioritize_imports(
                        processed_set, import_priorities, sequence, is_moniker)

            if not skip_monikered:
                # moniker imports are prioritized by the 'closest' use of the moniker to the starting doc.
                # so last one found in this recursion
                for imp in self.imports:
                    if imp._document and imp.moniker:
                        moniker_map[imp.moniker] = imp._document

                # if the document index is zero, the document being processed is the root of the imports chain.
                # in this case add the monikered imports to the end of the priorityMap.
                if self in priority_map and priority_map[self].priority == 0:
                    for doc in moniker_imports:
                        if doc not in priority_map:
                            priority_map[doc] = ImportInfo(sequence, True)
                            sequence += 1

        return sequence