def valueNumber(self) -> float: try: return float(self.valueString) except: Error.handleFromElement(element=self.element, message="Expected a valid number.") return 0.0 # To make mypy happy
def valueString(self) -> str: value = self.value if value is None: Error.handleFromElement(element=self.element, message="A value must be present.") assert value is not None return value
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])
def errorSymbolConflict_(element1: Element, element2: Element) -> None: message = Error.handleFromElement( element=element1, message="Symbol name is in conflict...", throw=False) message += Error.handleFromElement(element=element2, message="...with this one.", throw=False) raise Exception(message)
def validate(self) -> None: """ Validate the contracts. it checks the follow: - Valid contract types. """ for contract in self: contractTraits = AllContracts.allPublic.get(contract.type) if contractTraits is None: Error.handleFromElement( element=self.element, message="Contract of type '{}' is not supported.".format( contract.type))
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)
def _render( self, substitutions: typing.Union[SubstitutionsAccessor, SubstitutionWrapper] ) -> typing.Tuple[ResultType, SubstitutionWrapper]: sequence = self.parser.parse() *_, last = sequence if last.getAttrValue("category", None) in ["if", "else", "for", "macro"]: Error.handleFromElement(element=last, message="Unterminated control block.") visitor = Visitor(substitutions, *self.args, **self.kwargs) result = visitor.visit(sequence) return result, visitor.substitutions
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.")
def transform(entity: Type, nested: typing.List[str], reference: bool) -> TypeConversionCallableReturn: maybeContractMin = entity.contracts.get("min") isSigned = True if maybeContractMin is None or maybeContractMin.valueNumber < 0 else False maybeContractMax = entity.contracts.get("max") bits = 32 if maybeContractMax is not None: maxValue = maybeContractMax.valueNumber if maxValue < 2**8: bits = 8 elif maxValue < 2**16: bits = 16 elif maxValue < 2**32: bits = 32 elif maxValue < 2**64: bits = 64 else: Error.handleFromElement( element=entity.element, message="Value too large, max supported is 64-bit.") if isSigned: return "bzd::Int{}Type".format(bits), nested return "bzd::UInt{}Type".format(bits), nested
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
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
def error(self, message: str, throw: bool = True) -> str: return Error.handleFromElement(element=self.element, message=message, throw=throw)