Exemplo n.º 1
0
    def visitSubstitution(self, element: Element, result: ResultType) -> None:
        """
		Handle substitution.
		"""
        Error.assertHasAttr(element=element, attr="name")
        name = element.getAttr("name").value

        # Check if callable and if there are arguments
        arguments = element.getNestedSequence("argument")
        if arguments is None:
            value = self.resolveName(name=name)
        else:
            # Resolve all arguments
            args = []
            for arg in arguments:
                args.append(self.readValue(element=arg))
            value = self.resolveName(name, True, *args)

        # Process the pipes if any.
        pipes = element.getNestedSequence("pipe")
        if pipes:
            for pipe in pipes:
                Error.assertHasAttr(element=pipe, attr="name")
                value = self.resolveName(
                    pipe.getAttr("name").value, True, value)

        # Save the output
        assert isinstance(
            value, (int, float, str, pathlib.Path)
        ), "The resulting substitued value must be a number, a string or a path."
        self.appendSubstitution(element=element,
                                result=result,
                                string=str(value))
Exemplo n.º 2
0
    def processMacro(self, element: Element, *args: typing.Any) -> str:
        """
		Process a macro already defined.
		"""

        sequence = element.getNestedSequence("nested")
        assert sequence

        # Build the argument list
        argList = []
        argument = element.getNestedSequence("argument")
        assert argument is not None
        for arg in argument:
            Error.assertHasAttr(element=arg, attr="name")
            argList.append(arg.getAttr("name").value)

        # Sanity check
        Error.assertTrue(
            element=element,
            condition=len(argList) == len(args),
            message="Wrong number of argument(s), expected {}: {}".format(
                len(argList), ", ".join(argList)))

        for i, name in enumerate(argList):
            self.substitutions.register(element=element,
                                        key=name,
                                        value=args[i])

        # Process the template
        result = self._visit(sequence=sequence)

        for name in argList:
            self.substitutions.unregister(name)

        return "".join(result)
Exemplo n.º 3
0
 def toStringFromElement(element: Element,
                         attr: typing.Optional[str] = None,
                         message: str = "Error") -> str:
     context, start, end = element.makeContext(attr=attr)
     return Error.toString(context=context,
                           index=start,
                           end=end,
                           message=message)
Exemplo n.º 4
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
Exemplo n.º 5
0
    def visitForBlock(self, element: Element) -> ResultType:
        """
		Handle for loop block.
		"""

        Error.assertHasAttr(element=element, attr="value1")
        Error.assertHasAttr(element=element, attr="iterable")
        Error.assertHasSequence(element=element, sequence="nested")

        value1 = element.getAttr("value1").value
        value2 = element.getAttrValue("value2")

        sequence = element.getNestedSequence(kind="nested")
        assert sequence

        block: ResultType = []

        # Loop through the elements
        iterable = self.resolveName(name=element.getAttr("iterable").value)
        if value2 is None:
            for value in iterable:
                self.substitutions.register(element=element,
                                            key=value1,
                                            value=value)
                block += self._visit(sequence=sequence)
                self.substitutions.unregister(value1)
        else:
            iterablePair = iterable.items() if isinstance(
                iterable, dict) else enumerate(iterable)
            for key, value in iterablePair:
                self.substitutions.register(element=element,
                                            key=value1,
                                            value=key)
                self.substitutions.register(element=element,
                                            key=value2,
                                            value=value)
                block += self._visit(sequence=sequence)
                self.substitutions.unregister(value2)
                self.substitutions.unregister(value1)

        return block
Exemplo n.º 6
0
    def readValue(self, element: Element) -> typing.Any:
        """
		Read a value from an element.
		"""

        Error.assertHasAttr(element=element, attr="value")
        Error.assertHasAttr(element=element, attr="type")
        valueType = element.getAttr("type").value
        value = element.getAttr("value").value
        if valueType == "name":
            return self.resolveName(value)
        elif valueType == "number":
            return float(value)
        elif valueType == "string":
            return value
        elif valueType == "true":
            return True
        elif valueType == "false":
            return False
        Error.handleFromElement(element=element,
                                message="Unsupported value type.")
Exemplo n.º 7
0
    def visitIfBlock(self, element: Element, conditionStr: str) -> ResultType:
        """
		Handle if block.
		"""

        sequence = element.getNestedSequenceAssert(kind="nested")

        condition = self.evaluateCondition(conditionStr=conditionStr)
        self.followElse = not condition
        if condition:
            return self._visit(sequence=sequence)

        return []
Exemplo n.º 8
0
    def assertHasSequence(element: Element,
                          sequence: str,
                          throw: bool = True) -> typing.Optional[str]:
        """
		Ensures an element has a specific sequence.
		"""

        if not element.isNestedSequence(sequence):
            return Error.handleFromElement(
                element=element,
                attr=None,
                message="Mising mandatory sequence '{}'.".format(sequence),
                throw=throw)
        return None
Exemplo n.º 9
0
    def assertHasAttr(element: Element,
                      attr: str,
                      throw: bool = True) -> typing.Optional[str]:
        """
		Ensures an element has a specific attribute.
		"""

        if not element.isAttr(attr):
            return Error.handleFromElement(
                element=element,
                attr=None,
                message="Mising mandatory attribute '{}'.".format(attr),
                throw=throw)
        return None
Exemplo n.º 10
0
	def visitElement(self, element: Element, result: typing.List[str],
		nested: typing.Optional[typing.List[str]]) -> typing.List[str]:

		if element.isAttr("type"):

			entity = Type(element=element,
				kind="type",
				underlyingType="fqn_type",
				template="template_resolved" if self.isResolved else "template",
				argumentTemplate="argument_template_resolved" if self.isResolved else None,
				const="const")
			output = self.visitType(entity=entity,
				nested=[] if nested is None else nested,
				parameters=entity.parametersTemplateResolved)

		else:
			Error.assertHasAttr(element=element, attr="value")
			Error.assertTrue(element=element, condition=not nested, message="Value cannot have nested entities.")
			output = self.visitValue(value=element.getAttr("value").value, comment=element.getAttrValue("comment"))

		result.append(output)

		return result
Exemplo n.º 11
0
def elementToEntity(element: Element,
	extension: typing.Optional[typing.Dict[str, typing.Type[EntityType]]] = None) -> EntityType:
	"""
	Instantiate an entity from an element.
	"""

	Error.assertHasAttr(element=element, attr="category")
	category = element.getAttr("category").value

	if extension and category in extension:
		return extension[category](element=element)

	if category not in CATEGORY_TO_ENTITY:
		Error.handleFromElement(element=element, message="Unexpected element category: {}".format(category))

	return CATEGORY_TO_ENTITY[category](element=element)
Exemplo n.º 12
0
    def visitMacro(self, element: Element) -> None:
        """
		Handle macro definition block.
		"""
        Error.assertHasSequence(element=element, sequence="argument")
        Error.assertHasSequence(element=element, sequence="nested")
        Error.assertHasAttr(element=element, attr="name")

        name = element.getAttr("name").value
        Error.assertTrue(
            element=element,
            attr="name",
            condition=(name not in self.substitutions),
            message=
            "Name conflict with macro and an already existing name: '{}'.".
            format(name))

        # Register the macro
        self.substitutions.register(
            element=element,
            key=name,
            value=lambda *args: self.processMacro(element, *args))
Exemplo n.º 13
0
    def visitElement(self, element: Element, result: ResultType) -> ResultType:
        """
		Go through all elements and dispatch the action.
		"""

        Error.assertHasAttr(element=element, attr="category")
        category = element.getAttr("category").value

        try:

            # Raw content
            if category == "content":
                Error.assertHasAttr(element=element, attr="content")
                string = element.getAttr("content").value
                result.append(string)

            # Substitution
            elif category == "substitution":
                self.visitSubstitution(element=element, result=result)

            # Comments
            elif category == "comment":
                pass

            # End statement
            elif category == "end":
                # Reset the else flag here to make sure nested if without else do not trigger.
                self.followElse = False

            # For loop block
            elif category == "for":
                block = self.visitForBlock(element=element)
                self.appendBlock(element=element, result=result, block=block)

            # If block
            elif category == "if":
                Error.assertHasAttr(element=element, attr="condition")
                conditionStr = element.getAttr("condition").value
                block = self.visitIfBlock(element=element,
                                          conditionStr=conditionStr)
                self.appendBlock(element=element, result=result, block=block)

            # Else block
            elif category == "else":
                block = []
                if self.followElse:
                    conditionStr = element.getAttrValue("condition",
                                                        "True")  # type: ignore
                    block = self.visitIfBlock(element=element,
                                              conditionStr=conditionStr)
                self.appendBlock(element=element, result=result, block=block)

            # Macro block
            elif category == "macro":
                self.visitMacro(element=element)

            elif category == "include":
                block = self.visitInclude(element=element)
                self.appendBlock(element=element, result=result, block=block)

            else:
                raise Exception("Unsupported category: '{}'.".format(category))

        # Propagate processed exception to the top layer
        except ExceptionParser as e:
            raise e

        except Exception as e:
            Error.handleFromElement(element=element, message=str(e))

        return result
Exemplo n.º 14
0
 def __init__(self, namespace: typing.List[str]) -> None:
     super().__init__("namespace")
     for name in namespace:
         element = Element().setAttr("name", name)
         self.pushBackElementToNestedSequence(kind="name", element=element)
Exemplo n.º 15
0
 def metaToElement(meta: typing.Any) -> Element:
     return Element.fromSerialize(element=meta["e"],
                                  context=Context(path=Path(meta["p"])))
Exemplo n.º 16
0
    def visitElement(self, element: Element, result: T) -> T:
        """
		Main visitor, called each time a new element is discovered.
		"""

        entity = elementToEntity(element=element,
                                 extension=self.elementToEntityExtenstion)

        # Handle nested object
        if isinstance(entity, Nested):

            self.level += 1

            for category in CATEGORIES:
                sequence = element.getNestedSequence(category)
                if sequence is not None:
                    self.parents.append(
                        Parent(entity=entity, category=category))
                    nestedResult = self._visit(sequence, result)
                    self.entityToNested(category, entity, nestedResult, result)
                    self.parents.pop()

            self.level -= 1

            self.visitNestedEntities(entity, result)

        # Handle expression
        elif isinstance(entity, Expression):

            self.visitExpression(entity, result)

        # Handle method
        elif isinstance(entity, Method):

            self.visitMethod(entity, result)

        # Handle using
        elif isinstance(entity, Using):

            self.visitUsing(entity, result)

        # Handle using
        elif isinstance(entity, Enum):

            self.visitEnum(entity, result)

        # Handle namespace
        elif isinstance(entity, Namespace):

            Error.assertTrue(
                element=element,
                condition=(self.level == 0),
                message="Namespaces can only be declared at top level.")

            self.visitNamespace(entity, result)

            # Update the current namespace
            self.parents.append(Parent(entity=entity))

        # Handle use
        elif isinstance(entity, Use):

            self.visitUse(entity, result)

        # Should never go here
        else:
            Error.handleFromElement(element=element,
                                    message="Unexpected entity: {}".format(
                                        type(entity)))

        return result
Exemplo n.º 17
0
 def visitElement(self, element: Element,
                  result: typing.List[str]) -> typing.List[str]:
     Error.assertHasAttr(element=element, attr="name")
     result.append(element.getAttr("name").value)
     return result