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)
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))
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
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