Esempio n. 1
0
	def toResolvedSequence(self, resolver: "Resolver", varArgs: bool, onlyTypes: bool = False,
		onlyValues: bool = False) -> Sequence:
		"""
		Build the resolved sequence of those parameters.
		Must be called after mergeDefaults.
		"""
		sequence = SequenceBuilder()

		entries = self.itemsValuesOrTypes(resolver=resolver, varArgs=varArgs)
		if self.isNamed:
			entries = sorted(entries, key=lambda k: k[2].order)

		# Build the sequence
		from tools.bdl.entities.impl.fragment.type import Type
		for key, item, metadata in entries:
			if onlyTypes:
				Error.assertTrue(element=self.element,
					condition=isinstance(item, Type),
					message="Parameter '{}' is not a type.".format(key))
			if onlyValues:
				Error.assertTrue(element=self.element,
					condition=not isinstance(item, Type),
					message="Parameter '{}' is not a value.".format(key))
			if isinstance(item, str):
				element = ElementBuilder().setAttr(key="value", value=item)
			else:
				element = item.element.copy()
			if self.isNamed:
				ElementBuilder.cast(element, ElementBuilder).setAttr(key="key", value=key)
			sequence.pushBackElement(element)

		return sequence
Esempio n. 2
0
    def addParents(self, fqn: typing.Optional[str],
                   parents: typing.List[str]) -> None:
        """
		Add parents to the current entity.
		"""
        if fqn is None:
            updatedParents = {*self.getParents(), *parents}
        else:
            updatedParents = {*self.getParents(), fqn, *parents}
        ElementBuilder.cast(self.element,
                            ElementBuilder).setAttr("parents",
                                                    ";".join(updatedParents))
Esempio n. 3
0
    def add(element: Element,
            kind: str,
            values: typing.Optional[typing.List[str]] = None) -> None:
        """
		Add a contract to the element.
		"""
        contractElement = ElementBuilder().setAttr("type", kind)
        if values is not None:
            for value in values:
                valueElement = ElementBuilder().setAttr("value", value)
                contractElement.pushBackElementToNestedSequence(
                    kind="values", element=valueElement)
        ElementBuilder.cast(element,
                            ElementBuilder).pushBackElementToNestedSequence(
                                kind="contract", element=contractElement)
Esempio n. 4
0
    def resolve(self, contracts: "Contracts") -> None:
        """
		Merge a base contract into this one. The order is important, as type are inherited from the deepest base.
		"""

        elementBuilder = ElementBuilder.cast(self.element, ElementBuilder)
        for contract in reversed([*contracts]):
            # Check if the type already exists, if so attempt to merge the 2 types.
            existing = self.get(contract.type)
            if existing is not None:
                contractTraits = AllContracts.all.get(contract.type)
                assert contractTraits, "All contracts should have been validated already."
                try:
                    contract = contractTraits.resolveConflict(base=contract,
                                                              derived=existing)
                except Exception as e:
                    Error.handleFromElement(element=self.element,
                                            message=str(e))
                # Remove the existing contract if resolved into a new contract
                if contract is not None:
                    self.remove(contract.type)

            if contract is not None:
                elementBuilder.pushFrontElementToNestedSequence(
                    self.sequenceKind, contract.element)

        # Construct a dummy Validation to check the arguments
        maybeSchema = self.validationForAll
        if maybeSchema:
            Validation(schema=[maybeSchema])
Esempio n. 5
0
 def _setUnderlyingValue(self,
                         entity: "Entity",
                         fqn: typing.Optional[str] = None) -> None:
     elementBuilder = ElementBuilder.cast(self.element, ElementBuilder)
     if fqn is not None:
         elementBuilder.setAttr("fqn_value", fqn)
     elif entity.underlyingValue is not None:
         elementBuilder.setAttr("fqn_value", entity.underlyingValue)
     if entity.literal is not None:
         elementBuilder.setAttr("literal", entity.literal)
Esempio n. 6
0
	def resolve(self, resolver: "Resolver") -> "EntityType":
		"""
		Resolve the types and nested templates by updating their symbol to fqn.
		"""

		fqns = resolver.resolveFQN(name=self.kind).assertValue(element=self.element, attr=self.kindAttr)

		ElementBuilder.cast(self.element, ElementBuilder).updateAttr(self.kindAttr, ";".join(fqns))

		# Resolve the templates if available
		self.templates.resolve(resolver=resolver)
		templates = self.templates

		# Get and save the underlying type
		underlying = self.getEntityResolved(resolver=resolver)
		# Resolve the entity, this is needed only if the entity is defined after the one holding this type.
		underlying.resolveMemoized(resolver=resolver)

		if self.underlyingTypeAttr is not None and underlying.underlyingType is not None:
			ElementBuilder.cast(self.element, ElementBuilder).setAttr(self.underlyingTypeAttr,
				underlying.underlyingType)

		# Validate template arguments
		configTypes = underlying.getConfigTemplateTypes(resolver=resolver)
		if not configTypes:
			Error.assertTrue(element=self.element,
				condition=(not bool(self.templates)),
				attr=self.kindAttr,
				message="Type '{}' does not support template type arguments.".format(self.kind))
		else:

			templates.mergeDefaults(configTypes)

			# Validate the template arguments
			values = templates.getValuesOrTypesAsDict(resolver=resolver, varArgs=False)
			validation = underlying.makeValidationForTemplate(resolver=resolver, parameters=configTypes)
			assert validation, "Cannot be empty, already checked by the condition."
			resultValidate = validation.validate(values, output="return")
			Error.assertTrue(element=self.element,
				attr=self.kindAttr,
				condition=bool(resultValidate),
				message=str(resultValidate))

			# Save the resolved template only after the validation is completed.
			sequence = templates.toResolvedSequence(resolver=resolver, varArgs=False, onlyTypes=True)
			ElementBuilder.cast(self.element, ElementBuilder).setNestedSequence("{}_resolved".format(self.templateAttr),
				sequence)

		# Resolve contract
		self.contracts.resolve(underlying.contracts)

		return underlying
Esempio n. 7
0
	def itemsValuesOrTypes(self, resolver: "Resolver", varArgs: bool) -> typing.List[typing.Tuple[str, ResolvedType,
		Metadata]]:
		"""
        Iterate through the list and return values or types.
        """

		values: typing.List[typing.Tuple[str, ResolvedType, Metadata]] = []

		for key, expression, metadata in self.itemsMetadata():

			if expression.isVarArgs and not varArgs:
				continue

			if expression.literal is not None:
				values.append((key, expression.literal, metadata))

			elif expression.underlyingValue is not None:
				value: ResolvedType = resolver.getEntityResolved(fqn=expression.underlyingValue).assertValue(
					element=expression.element)

				# If these are default arguments, use the default value.
				if metadata.default:
					from tools.bdl.entities.impl.expression import Expression
					assert isinstance(value, Expression)
					if value.literal:
						# I beleive that this code path is never used.
						value = value.literal
					elif value.isName:
						# Create an unamed value
						element = ElementBuilder.cast(value.element.copy(), ElementBuilder).removeAttr(key="name").get()
						value = Expression(element)

				values.append((key, value, metadata))

			else:
				values.append((key, expression.type, metadata))

		return values
Esempio n. 8
0
    def resolve(self, resolver: "Resolver") -> None:
        """
		Resolve entities.
		"""
        if self.isValue:
            return

        entity = self.type.resolve(resolver=resolver)

        # Set the underlying value
        if self.isParameters:

            # The type must represent a type (not a value) and have a valid FQN.
            self.assertTrue(
                condition=entity.isRoleType,
                message="Cannot instantiate a value from another value.")
            self.assertTrue(condition=self.isFQN,
                            message="The value must have a FQN.")
            # TODO: it is possible that the expression does not have a FQN, in case the expression is resolved through another entity.
            self._setUnderlyingValue(entity=self, fqn=self.fqn)

        else:
            self._setUnderlyingValue(entity=entity)

        # Generate the argument list and resolve it
        if self.isParameters:
            parameters = self.parameters
            assert parameters is not None
            parameters.resolve(resolver=resolver)
        else:
            parameters = Parameters(element=self.element)

        # Merge its default values
        defaults = self.getConfigValues(resolver=resolver)
        parameters.mergeDefaults(defaults)

        # Read the validation for the value. it comes in part from the direct underlying type, contract information
        # directly associated with this expression do not apply to the current validation.
        validation = self._makeValueValidation(resolver=resolver,
                                               parameters=defaults,
                                               contracts=self.contracts)
        if validation is not None:
            arguments = parameters.getValuesOrTypesAsDict(resolver=resolver,
                                                          varArgs=False)
            result = validation.validate(arguments, output="return")
            Error.assertTrue(element=self.element,
                             attr="type",
                             condition=bool(result),
                             message=str(result))

        # Save the resolved parameters (values and templates), only after the validation is completed.
        argumentValues = parameters.copy(template=False)
        sequence = argumentValues.toResolvedSequence(resolver=resolver,
                                                     varArgs=False,
                                                     onlyValues=True)
        ElementBuilder.cast(self.element, ElementBuilder).setNestedSequence(
            "argument_resolved", sequence)

        argumentTemplates = parameters.copy(template=True)
        sequence = argumentTemplates.toResolvedSequence(resolver=resolver,
                                                        varArgs=False,
                                                        onlyValues=True)
        ElementBuilder.cast(self.element, ElementBuilder).setNestedSequence(
            "argument_template_resolved", sequence)
Esempio n. 9
0
 def _setUnderlyingType(self, fqn: str) -> None:
     ElementBuilder.cast(self.element,
                         ElementBuilder).setAttr("fqn_type", fqn)
Esempio n. 10
0
    def markAsResolved(self) -> None:
        """
		Mark an entity as resolved.
		"""
        ElementBuilder.cast(self.element,
                            ElementBuilder).setAttr("resolved", "1")