232 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Python
		
	
	
| """Instantiate a class and its members."""
 | |
| 
 | |
| import gtwrap.interface_parser as parser
 | |
| from gtwrap.template_instantiator.constructor import InstantiatedConstructor
 | |
| from gtwrap.template_instantiator.helpers import (InstantiationHelper,
 | |
|                                                   instantiate_args_list,
 | |
|                                                   instantiate_name,
 | |
|                                                   instantiate_return_type,
 | |
|                                                   instantiate_type)
 | |
| from gtwrap.template_instantiator.method import (InstantiatedMethod,
 | |
|                                                  InstantiatedStaticMethod)
 | |
| 
 | |
| 
 | |
| class InstantiatedClass(parser.Class):
 | |
|     """
 | |
|     Instantiate the class defined in the interface file.
 | |
|     """
 | |
| 
 | |
|     def __init__(self, original: parser.Class, instantiations=(), new_name=''):
 | |
|         """
 | |
|         Template <T, U>
 | |
|         Instantiations: [T1, U1]
 | |
|         """
 | |
|         self.original = original
 | |
|         self.instantiations = instantiations
 | |
| 
 | |
|         self.template = None
 | |
|         self.is_virtual = original.is_virtual
 | |
|         self.parent = original.parent
 | |
| 
 | |
|         # If the class is templated, check if the number of provided instantiations
 | |
|         # match the number of templates, else it's only a partial instantiation which is bad.
 | |
|         if original.template:
 | |
|             assert len(original.template.typenames) == len(
 | |
|                 instantiations), "Typenames and instantiations mismatch!"
 | |
| 
 | |
|         # Get the instantiated name of the class. E.g. FuncDouble
 | |
|         self.name = instantiate_name(
 | |
|             original.name, instantiations) if not new_name else new_name
 | |
| 
 | |
|         # Check for typenames if templated.
 | |
|         # By passing in typenames, we can gracefully handle both templated and non-templated classes
 | |
|         # This will allow the `This` keyword to be used in both templated and non-templated classes.
 | |
|         typenames = self.original.template.typenames if self.original.template else []
 | |
| 
 | |
|         # Instantiate the parent class, constructors, static methods, properties, respectively.
 | |
|         self.parent_class = self.instantiate_parent_class(typenames)
 | |
|         self.ctors = self.instantiate_ctors(typenames)
 | |
|         self.static_methods = self.instantiate_static_methods(typenames)
 | |
|         self.properties = self.instantiate_properties(typenames)
 | |
| 
 | |
|         # Instantiate all operator overloads
 | |
|         self.operators = self.instantiate_operators(typenames)
 | |
| 
 | |
|         # Set enums
 | |
|         self.enums = original.enums
 | |
| 
 | |
|         # Instantiate all instance methods
 | |
|         self.methods = self.instantiate_methods(typenames)
 | |
| 
 | |
|         super().__init__(
 | |
|             self.template,
 | |
|             self.is_virtual,
 | |
|             self.name,
 | |
|             [self.parent_class],
 | |
|             self.ctors,
 | |
|             self.methods,
 | |
|             self.static_methods,
 | |
|             self.properties,
 | |
|             self.operators,
 | |
|             self.enums,
 | |
|             parent=self.parent,
 | |
|         )
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return "{virtual}Class {cpp_class} : {parent_class}\n"\
 | |
|             "{ctors}\n{static_methods}\n{methods}\n{operators}".format(
 | |
|                virtual="virtual " if self.is_virtual else '',
 | |
|                cpp_class=self.to_cpp(),
 | |
|                parent_class=self.parent,
 | |
|                ctors="\n".join([repr(ctor) for ctor in self.ctors]),
 | |
|                static_methods="\n".join([repr(m)
 | |
|                                          for m in self.static_methods]),
 | |
|                 methods="\n".join([repr(m) for m in self.methods]),
 | |
|                operators="\n".join([repr(op) for op in self.operators])
 | |
|             )
 | |
| 
 | |
|     def instantiate_parent_class(self, typenames):
 | |
|         """
 | |
|         Instantiate the inherited parent names.
 | |
| 
 | |
|         Args:
 | |
|             typenames: List of template types to instantiate.
 | |
| 
 | |
|         Return: List of constructors instantiated with provided template args.
 | |
|         """
 | |
| 
 | |
|         if isinstance(self.original.parent_class, parser.type.TemplatedType):
 | |
|             return instantiate_type(
 | |
|                 self.original.parent_class, typenames, self.instantiations,
 | |
|                 parser.Typename(self.namespaces())).typename
 | |
|         else:
 | |
|             return self.original.parent_class
 | |
| 
 | |
|     def instantiate_ctors(self, typenames):
 | |
|         """
 | |
|         Instantiate the class constructors.
 | |
| 
 | |
|         Args:
 | |
|             typenames: List of template types to instantiate.
 | |
| 
 | |
|         Return: List of constructors instantiated with provided template args.
 | |
|         """
 | |
| 
 | |
|         helper = InstantiationHelper(
 | |
|             instantiation_type=InstantiatedConstructor)
 | |
| 
 | |
|         instantiated_ctors = helper.multilevel_instantiation(
 | |
|             self.original.ctors, typenames, self)
 | |
| 
 | |
|         return instantiated_ctors
 | |
| 
 | |
|     def instantiate_static_methods(self, typenames):
 | |
|         """
 | |
|         Instantiate static methods in the class.
 | |
| 
 | |
|         Args:
 | |
|             typenames: List of template types to instantiate.
 | |
| 
 | |
|         Return: List of static methods instantiated with provided template args.
 | |
|         """
 | |
|         helper = InstantiationHelper(
 | |
|             instantiation_type=InstantiatedStaticMethod)
 | |
| 
 | |
|         instantiated_static_methods = helper.multilevel_instantiation(
 | |
|             self.original.static_methods, typenames, self)
 | |
| 
 | |
|         return instantiated_static_methods
 | |
| 
 | |
|     def instantiate_methods(self, typenames):
 | |
|         """
 | |
|         Instantiate regular methods in the class.
 | |
| 
 | |
|         Args:
 | |
|             typenames: List of template types to instantiate.
 | |
| 
 | |
|         Return: List of methods instantiated with provided template args.
 | |
|         """
 | |
|         instantiated_methods = []
 | |
| 
 | |
|         helper = InstantiationHelper(instantiation_type=InstantiatedMethod)
 | |
| 
 | |
|         instantiated_methods = helper.multilevel_instantiation(
 | |
|             self.original.methods, typenames, self)
 | |
| 
 | |
|         return instantiated_methods
 | |
| 
 | |
|     def instantiate_operators(self, typenames):
 | |
|         """
 | |
|         Instantiate the class-level template in the operator overload.
 | |
| 
 | |
|         Args:
 | |
|             typenames: List of template types to instantiate.
 | |
| 
 | |
|         Return: List of methods instantiated with provided template args on the class.
 | |
|         """
 | |
|         instantiated_operators = []
 | |
|         for operator in self.original.operators:
 | |
|             instantiated_args = instantiate_args_list(
 | |
|                 operator.args.list(),
 | |
|                 typenames,
 | |
|                 self.instantiations,
 | |
|                 self.cpp_typename(),
 | |
|             )
 | |
|             instantiated_operators.append(
 | |
|                 parser.Operator(
 | |
|                     name=operator.name,
 | |
|                     operator=operator.operator,
 | |
|                     return_type=instantiate_return_type(
 | |
|                         operator.return_type,
 | |
|                         typenames,
 | |
|                         self.instantiations,
 | |
|                         self.cpp_typename(),
 | |
|                     ),
 | |
|                     args=parser.ArgumentList(instantiated_args),
 | |
|                     is_const=operator.is_const,
 | |
|                     parent=self,
 | |
|                 ))
 | |
|         return instantiated_operators
 | |
| 
 | |
|     def instantiate_properties(self, typenames):
 | |
|         """
 | |
|         Instantiate the class properties.
 | |
| 
 | |
|         Args:
 | |
|             typenames: List of template types to instantiate.
 | |
| 
 | |
|         Return: List of properties instantiated with provided template args.
 | |
|         """
 | |
|         instantiated_ = instantiate_args_list(
 | |
|             self.original.properties,
 | |
|             typenames,
 | |
|             self.instantiations,
 | |
|             self.cpp_typename(),
 | |
|         )
 | |
|         # Convert to type Variable
 | |
|         instantiated_properties = [
 | |
|             parser.Variable(ctype=[arg.ctype],
 | |
|                             name=arg.name,
 | |
|                             default=arg.default) for arg in instantiated_
 | |
|         ]
 | |
|         return instantiated_properties
 | |
| 
 | |
|     def cpp_typename(self):
 | |
|         """
 | |
|         Return a parser.Typename including namespaces and cpp name of this
 | |
|         class.
 | |
|         """
 | |
|         if self.original.template:
 | |
|             name = "{}<{}>".format(
 | |
|                 self.original.name,
 | |
|                 ", ".join([inst.to_cpp() for inst in self.instantiations]))
 | |
|         else:
 | |
|             name = self.original.name
 | |
|         namespaces_name = self.namespaces()
 | |
|         namespaces_name.append(name)
 | |
|         return parser.Typename(namespaces_name)
 | |
| 
 | |
|     def to_cpp(self):
 | |
|         """Generate the C++ code for wrapping."""
 | |
|         return self.cpp_typename().to_cpp()
 |