示例#1
0
    def insert(self,
               name: typing.Optional[str],
               namespace: typing.List[str],
               path: typing.Optional[Path],
               element: Element,
               category: str,
               conflicts: bool = False) -> str:
        """
		Insert a new element into the symbol map.
		Args:
			fqn: Full qualified name.
			path: Path associated with the element.
			element: Element to be registered.
			category: Category associated with the element, will be used for filtering.
			conflicts: Handle symbol FQN conflicts.
		"""
        if name is None:
            # These are the unnamed elements that should be progpagated to other translation units.
            if category in {CATEGORY_COMPOSITION, CATEGORY_GLOBAL_COMPOSITION}:
                fqn = FQN.makeUnique(namespace=namespace)
            # If not, they will be kept private.
            else:
                fqn = FQN.makeUniquePrivate()
        else:
            # Build the symbol name.
            fqn = FQN.fromNamespace(name=name, namespace=namespace)
        assert fqn is not None

        # Save the FQN to the element, so that it can be found during [de]serialization.
        # This is also used to refer to the element with the symbol tree, the top-level ones only.
        # In addition, it is assumed that during while resolved any element have a valid FQN.
        ElementBuilder.cast(element, ElementBuilder).setAttr("fqn", fqn)

        if self.contains(fqn=fqn):
            originalElement = self.getEntityResolved(fqn=fqn).assertValue(
                element=element).element
            if not conflicts or element != originalElement:
                SymbolMap.errorSymbolConflict_(element, originalElement)

        self.map[fqn] = {
            "c": category,
            "p": path.as_posix() if path is not None else "",
            "e": None
        }

        # Resolve context
        context, _, _ = element.context.resolve()
        element.context = context

        # The element is also added to the entity map, to allow further modification that will
        # be written when serialize is called.
        self.entities[fqn] = elementToEntity(element=element)

        return fqn
示例#2
0
    def resolveFQN(self, name: str) -> resolveFQNResult:
        """
		Find the fully qualified name of a given a name and a namespace.
		Note, name can be a partial fqn.
		"""
        maybeFQN = self.resolveShallowFQN(name=name)
        if not maybeFQN:
            return resolveFQNResult.makeError(maybeFQN.error)

        fqn: typing.Optional[str]
        fqn, unresolvedFQN = maybeFQN.value

        # List of matching FQNs
        fqns: typing.List[str] = [fqn]

        # Re-iterate the process with the next items
        for nextName in unresolvedFQN:
            entity = self.getEntityResolved(fqn=fqn).value
            potentialNamespaceFQNs = [fqn]
            # If it has an underlying type, add it to the list as well as its parents (if any).
            if entity.underlyingType is not None:
                potentialNamespaceFQNs += [
                    entity.underlyingType
                ] + entity.getEntityUnderlyingTypeResolved(
                    resolver=self).getParents()
            # Check if there is any match.
            fqn = None
            for potentialNamespaceFQN in potentialNamespaceFQNs:
                potentialFQN = FQN.fromNamespace(
                    name=nextName,
                    namespace=FQN.toNamespace(potentialNamespaceFQN))
                if self.symbols.contains(fqn=potentialFQN,
                                         exclude=self.exclude):
                    fqn = potentialFQN
                    break
            if fqn is None:
                return resolveFQNResult.makeError(
                    "Symbol '{}' from '{}' in namespace '{}' could not be resolved."
                    .format(nextName, name, ".".join(self.namespace)
                            ) if self.namespace else
                    "Symbol '{}' from '{}' could not be resolved.".
                    format(nextName, name))
            fqns.append(fqn)

        # Return the final FQN.
        return resolveFQNResult(fqns)
示例#3
0
    def visitType(self, entity: Type, nested: typing.List[str],
                  parameters: ResolvedParameters) -> str:
        """
		Called when an element needs to be formatted.
		"""

        # Add arguments template to the nested mix.
        nested += self.declareParametersResolvedValues(parameters)

        outputList: typing.List[str] = []
        output: str
        for index, fqn in enumerate(entity.kinds):
            if fqn in knownTypes:
                if callable(knownTypes[fqn].transform):
                    output, nested = knownTypes[fqn].transform(
                        entity, nested, self.isReference)
                else:
                    output = knownTypes[fqn].transform
            else:
                namespace = FQN.toNamespace(fqn)
                if index == 0:
                    if self.isNamespaceToFQN:
                        assert self.namespaceToFQN is not None
                        output = self.namespaceToFQN(namespace)
                    else:
                        output = "::".join(namespace)
                else:
                    output = namespace[-1]
            outputList.append(output)
        output = ".".join(outputList)

        # Apply the nested template if any.
        if nested:
            output += "<{}>".format(", ".join(nested))

        if not self.isTopLevel:
            # TODO: support if there is no value.
            if entity.parametersResolved:
                output += "{{{}}}".format(", ".join([
                    expression.value
                    for expression in entity.parametersResolved
                ]))
        else:
            if self.definition:
                if entity.underlyingType in knownTypes and knownTypes[
                        entity.underlyingType].constexpr:
                    output = "constexpr " + output

        # Apply the reference if any.
        if self.isReference:
            output += "&"

        # Apply const if needed.
        if entity.const and (not self.isTopLevel or not self.nonConst):
            output = "const " + output

        return output
示例#4
0
    def resolveShallowFQN(self, name: str) -> ResolveShallowFQNResult:
        """
		Find the fully qualified name of a given a name and a namespace.
		Note, name can be a partial fqn.
		"""
        nameFirst = FQN.toNamespace(name)[0]

        if nameFirst == "this":
            if self.this is None:
                return ResolveShallowFQNResult.makeError(
                    "Keyword 'this' must be used in an object context.")
            nameFirst = self.this

        # Look for a symbol match of the first part of the name.
        potentialNamespace = self.namespace.copy()
        while True:
            fqn = FQN.fromNamespace(name=nameFirst,
                                    namespace=potentialNamespace)
            if self.symbols.contains(fqn=fqn, exclude=self.exclude):
                break
            if not potentialNamespace:
                return ResolveShallowFQNResult.makeError(
                    "Symbol '{}' in namespace '{}' could not be resolved.".
                    format(nameFirst, ".".join(self.namespace)) if self.
                    namespace else "Symbol '{}' could not be resolved.".
                    format(nameFirst))
            potentialNamespace.pop()

        # Attempt to resolve as much as possible.
        remainingNamespace = FQN.toNamespace(name)[1:]
        while remainingNamespace:
            potentialFQN = FQN.fromNamespace(name=remainingNamespace[0],
                                             namespace=FQN.toNamespace(fqn))
            if not self.symbols.contains(fqn=potentialFQN,
                                         exclude=self.exclude):
                break
            remainingNamespace.pop(0)
            fqn = potentialFQN

        # Return the FQN and the unresolved rest.
        return ResolveShallowFQNResult((fqn, remainingNamespace))
示例#5
0
    def getEntity(self,
                  fqn: str,
                  exclude: typing.Optional[typing.List[str]] = None
                  ) -> Result[EntityType]:
        """
		Return an element from the symbol map and resolves underlying types if needed.
		"""

        namespace = []
        result = None
        for name in FQN.toNamespace(fqn):
            namespace.append(name)
            result = self.getEntityResolved(
                fqn=FQN.fromNamespace(namespace=namespace), exclude=exclude)
            if not result:
                continue
            if result.value.underlyingType is not None:
                namespace = FQN.toNamespace(result.value.underlyingType)

        if not result:
            return Result.makeError(
                "Could not resolve symbol '{}'.".format(fqn))

        return Result(result.value)
示例#6
0
    def update(self, symbols: "SymbolMap") -> None:
        """
		Register multiple symbols.
		"""
        for fqn, element in symbols.map.items():

            # Ignore private entries
            if FQN.isPrivate(fqn):
                continue
            existingElement = self._get(fqn=fqn)
            if existingElement is not None and element["p"] != existingElement[
                    "p"]:
                SymbolMap.errorSymbolConflict_(
                    SymbolMap.metaToElement(element),
                    SymbolMap.metaToElement(existingElement))
            self.map[fqn] = element
示例#7
0
def fqnToAdapterStr(fqn: str) -> str:
    split = FQN.toNamespace(fqn)
    split.insert(-1, "adapter")
    return "::".join(split)
示例#8
0
def fqnToStr(fqn: str) -> str:
    return "::".join(FQN.toNamespace(fqn))
示例#9
0
def fqnToNameStr(fqn: str) -> str:
    split = FQN.toNamespace(fqn)
    return "_".join(split)
示例#10
0
    def close(self) -> None:
        """
		Close the map to prevent any further editing.
		"""

        # Create serialized blobs for elements present in the entities map.
        removeFQNs: typing.Set[str] = set()
        for fqn, entity in self.entities.items():

            # Ignore builtins
            if fqn in self.builtins:
                continue

            entity.assertTrue(
                condition=fqn in self.map,
                message=
                "Entry '{}' was not properly created before being added to the entities map."
                .format(fqn))
            element = entity.element

            # Remove nested element and change them to references.
            if any([
                    element.isNestedSequence(category)
                    for category in CATEGORIES
            ]):

                preparedElement = element.copy(ignoreNested=CATEGORIES)
                for category in CATEGORIES:
                    nested = element.getNestedSequence(category)
                    if nested is not None:
                        sequence = SequenceBuilder()
                        for nestedElement in nested:
                            if nestedElement.isAttr("fqn"):
                                fqnNested = nestedElement.getAttr("fqn").value
                                # Remove private FQNs and keep them nested.
                                # This is needed because when merging nested structure, some config
                                # for example have unamed elements and need to be copied with the rest.
                                if FQN.isPrivate(fqnNested):
                                    removeFQNs.add(fqnNested)
                                    ElementBuilder.cast(
                                        nestedElement,
                                        ElementBuilder).removeAttr("fqn")
                                    sequence.pushBackElement(nestedElement)
                                else:
                                    sequence.pushBackElement(
                                        self.makeReference(fqnNested))
                            else:
                                sequence.pushBackElement(nestedElement)
                        if sequence:
                            preparedElement.setNestedSequence(
                                category, sequence)
                element = preparedElement

            # Serialize the element to the map.
            self.map[fqn]["e"] = element.serialize()

        # Remove some of the FQNs that have been copied.
        for fqn in removeFQNs:
            del self.map[fqn]

        # Sanity check to ensure that all entries in the map are valid.
        for fqn, entry in self.map.items():
            assert "e" in entry and entry[
                "e"], "Invalid element in the map: {}.".format(entry)
            assert "c" in entry and entry[
                "c"], "Invalid category in the map: {}.".format(entry)
            assert "p" in entry, "Missing path in the map: {}.".format(entry)

        # Mark as closed.
        self.isClosed = True
示例#11
0
    def makeFQN(self, name: str) -> str:
        """
		Create an FQN out of a name.
		"""
        return FQN.fromNamespace(name=name, namespace=self.namespace)
示例#12
0
 def namespaceToFQN(namespace: typing.List[str]) -> str:
     fqn = FQN.fromNamespace(namespace=namespace)
     assert registry is not None
     if fqn in registry:
         return "registry.{}_".format(fqnToNameStr(fqn))
     return "::".join(namespace)
示例#13
0
 def namespace(self) -> typing.List[str]:
     return FQN.toNamespace(self.fqn)[:-1]