1 """Various helpers for instantiation.""" 4 from copy
import deepcopy
5 from typing
import List, Sequence, Union
9 ClassMembers = Union[parser.Constructor, parser.Method, parser.StaticMethod,
10 parser.GlobalFunction, parser.Operator, parser.Variable,
12 InstantiatedMembers = Union[
'InstantiatedConstructor',
'InstantiatedMethod',
13 'InstantiatedStaticMethod',
14 'InstantiatedGlobalFunction']
18 str_arg_typename: str):
20 Check if the template given by `str_arg_typename` is a scoped template e.g. T::Value, 21 and if so, return what template from `template_typenames` and 22 the corresponding index matches the scoped template correctly. 24 for idx, template
in enumerate(template_typenames):
25 if "::" in str_arg_typename
and \
26 template
in str_arg_typename.split(
"::"):
33 template_typenames: Sequence[str],
34 instantiations: Sequence[parser.Typename],
35 cpp_typename: parser.Typename,
36 instantiated_class:
'InstantiatedClass' =
None) -> parser.Type:
38 Instantiate template typename for `ctype`. 41 ctype: The original argument type. 42 template_typenames: List of strings representing the templates. 43 instantiations: List of the instantiations of the templates in `template_typenames`. 44 cpp_typename: Full-namespace cpp class name of this instantiation 45 to replace for arguments of type named `This`. 46 instiated_class: The instantiated class which, if provided, 47 will be used for instantiating `This`. 50 If `ctype`'s name is in the `template_typenames`, return the 51 corresponding type to replace in `instantiations`. 52 If ctype name is `This`, return the new typename `cpp_typename`. 53 Otherwise, return the original ctype. 56 ctype = deepcopy(ctype)
59 if ctype.typename.instantiations:
60 for idx, instantiation
in enumerate(ctype.typename.instantiations):
61 if instantiation.name
in template_typenames:
62 template_idx = template_typenames.index(instantiation.name)
63 ctype.typename.instantiations[idx].name =\
64 instantiations[template_idx]
67 str_arg_typename =
str(ctype.typename)
79 instantiation = deepcopy(instantiations[scoped_idx])
81 instantiation.name = str_arg_typename.replace(scoped_template,
84 typename=instantiation,
85 is_const=ctype.is_const,
86 is_shared_ptr=ctype.is_shared_ptr,
89 is_basic=ctype.is_basic,
92 elif str_arg_typename
in template_typenames:
93 idx = template_typenames.index(str_arg_typename)
95 typename=instantiations[idx],
96 is_const=ctype.is_const,
97 is_shared_ptr=ctype.is_shared_ptr,
100 is_basic=ctype.is_basic,
104 elif str_arg_typename ==
'This':
107 if instantiated_class:
108 name = instantiated_class.original.name
109 namespaces_name = instantiated_class.namespaces()
110 namespaces_name.append(name)
111 cpp_typename = parser.Typename(
113 instantiations=instantiated_class.instantiations)
116 typename=cpp_typename,
117 is_const=ctype.is_const,
118 is_shared_ptr=ctype.is_shared_ptr,
121 is_basic=ctype.is_basic,
125 elif 'This' in str_arg_typename:
127 if 'This' in ctype.typename.namespaces:
130 namespace_idx = ctype.typename.namespaces.index(
'This')
131 ctype.typename.namespaces[namespace_idx] = cpp_typename.name
134 for idx, instantiation
in enumerate(ctype.typename.instantiations):
135 if 'This' in instantiation.namespaces:
136 ctype.typename.instantiations[idx].namespaces = \
137 cpp_typename.namespaces + [cpp_typename.name]
145 args_list: Sequence[parser.Argument],
146 template_typenames: Sequence[parser.template.Typename],
147 instantiations: Sequence, cpp_typename: parser.Typename):
149 Instantiate template typenames in an argument list. 150 Type with name `This` will be replaced by @p `cpp_typename`. 152 @param[in] args_list A list of `parser.Argument` to instantiate. 153 @param[in] template_typenames List of template typenames to instantiate, 154 e.g. ['T', 'U', 'V'].
155 @param[in] instantiations List of specific types to instantiate, each
156 associated with each template typename. Each type is a parser.Typename,
157 including its name and full namespaces.
158 @param[in] cpp_typename Full-namespace cpp class name of this instantiation
159 to replace for arguments of type named `This`.
160 @return A new list of parser.Argument which types are replaced with their
163 instantiated_args = []
164 for arg in args_list:
165 new_type = instantiate_type(arg.ctype, template_typenames,
166 instantiations, cpp_typename)
167 instantiated_args.append(
168 parser.Argument(name=arg.name, ctype=new_type,
169 default=arg.default))
170 return instantiated_args
173 def instantiate_return_type(
174 return_type: parser.ReturnType,
175 template_typenames: Sequence[parser.template.Typename],
176 instantiations: Sequence[parser.Typename],
177 cpp_typename: parser.Typename,
178 instantiated_class: 'InstantiatedClass' = None):
179 """Instantiate the return type."""
180 new_type1 = instantiate_type(return_type.type1,
184 instantiated_class=instantiated_class)
185 if return_type.type2:
186 new_type2 = instantiate_type(return_type.type2,
190 instantiated_class=instantiated_class)
193 return parser.ReturnType(new_type1, new_type2)
196 def instantiate_name(original_name: str,
197 instantiations: Sequence[parser.Typename]):
199 Concatenate instantiated types with `original_name` to form a new
202 NOTE: To avoid conflicts, we should include the instantiation's
203 namespaces, but that is too verbose.
205 instantiated_names = []
206 for inst in instantiations:
207 # Ensure the first character of the type is capitalized
208 name = inst.instantiated_name()
209 # Using `capitalize` on the complete name causes other caps to be lower case
210 instantiated_names.append(name.replace(name[0], name[0].capitalize()))
212 return "{}{}".format(original_name, "".join(instantiated_names))
215 class InstantiationHelper:
217 Helper class for instantiation templates.
218 Requires that `instantiation_type` defines a class method called
219 `construct` to generate the appropriate object type.
221 Signature for `construct` should be
225 class_instantiations,
226 method_instantiations,
231 def __init__(self, instantiation_type: InstantiatedMembers):
232 self.instantiation_type = instantiation_type
234 def instantiate(self, instantiated_methods: List[InstantiatedMembers],
235 method: ClassMembers, typenames: Sequence[str],
236 class_instantiations: Sequence[parser.Typename],
237 method_instantiations: Sequence[parser.Typename],
238 parent: 'InstantiatedClass'):
240 Instantiate both the class and method level templates.
242 instantiations = class_instantiations + method_instantiations
244 instantiated_args = instantiate_args_list(method.args.list(),
245 typenames, instantiations,
246 parent.cpp_typename())
248 instantiated_methods.append(
249 self.instantiation_type.construct(method,
251 class_instantiations,
252 method_instantiations,
256 return instantiated_methods
258 def multilevel_instantiation(self, methods_list: Sequence[ClassMembers],
259 typenames: Sequence[str],
260 parent: 'InstantiatedClass'):
262 Helper to instantiate methods at both the class and method level.
265 methods_list: The list of methods in the class to instantiated.
266 typenames: List of class level template parameters, e.g. ['T'].
267 parent: The instantiated class to which `methods_list` belongs.
269 instantiated_methods = []
271 for method in methods_list:
272 # We creare a copy since we will modify the typenames list.
273 method_typenames = deepcopy(typenames)
275 if isinstance(method.template, parser.template.Template):
276 method_typenames.extend(method.template.typenames)
278 # Get all combinations of template args
279 for instantiations in itertools.product(
280 *method.template.instantiations):
282 instantiated_methods = self.instantiate(
283 instantiated_methods,
285 typenames=method_typenames,
286 class_instantiations=parent.instantiations,
287 method_instantiations=list(instantiations),
291 # If no constructor level templates, just use the class templates
292 instantiated_methods = self.instantiate(
293 instantiated_methods,
295 typenames=method_typenames,
296 class_instantiations=parent.instantiations,
297 method_instantiations=[],
300 return instantiated_methods
def instantiate_args_list