1d169d70bSTobias Grosser /*
2d169d70bSTobias Grosser  * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
3d169d70bSTobias Grosser  *
4d169d70bSTobias Grosser  * Redistribution and use in source and binary forms, with or without
5d169d70bSTobias Grosser  * modification, are permitted provided that the following conditions
6d169d70bSTobias Grosser  * are met:
7d169d70bSTobias Grosser  *
8d169d70bSTobias Grosser  *    1. Redistributions of source code must retain the above copyright
9d169d70bSTobias Grosser  *       notice, this list of conditions and the following disclaimer.
10d169d70bSTobias Grosser  *
11d169d70bSTobias Grosser  *    2. Redistributions in binary form must reproduce the above
12d169d70bSTobias Grosser  *       copyright notice, this list of conditions and the following
13d169d70bSTobias Grosser  *       disclaimer in the documentation and/or other materials provided
14d169d70bSTobias Grosser  *       with the distribution.
15d169d70bSTobias Grosser  *
16d169d70bSTobias Grosser  * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY
17d169d70bSTobias Grosser  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d169d70bSTobias Grosser  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19*3f9bf9f4Spatacca  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOBIAS GROSSER OR
20d169d70bSTobias Grosser  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21d169d70bSTobias Grosser  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22d169d70bSTobias Grosser  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23d169d70bSTobias Grosser  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24d169d70bSTobias Grosser  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25d169d70bSTobias Grosser  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26d169d70bSTobias Grosser  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27d169d70bSTobias Grosser  *
28d169d70bSTobias Grosser  * The views and conclusions contained in the software and documentation
29d169d70bSTobias Grosser  * are those of the authors and should not be interpreted as
30d169d70bSTobias Grosser  * representing official policies, either expressed or implied, of
31d169d70bSTobias Grosser  * Tobias Grosser.
32d169d70bSTobias Grosser  */
33d169d70bSTobias Grosser 
34d169d70bSTobias Grosser #include <iostream>
35d169d70bSTobias Grosser #include <string>
36d169d70bSTobias Grosser #include <vector>
37d169d70bSTobias Grosser 
38d169d70bSTobias Grosser #include "cpp.h"
39d169d70bSTobias Grosser #include "isl_config.h"
40d169d70bSTobias Grosser 
41*3f9bf9f4Spatacca /* Determine the isl types from which the given class can be implicitly
42*3f9bf9f4Spatacca  * constructed using a unary constructor.
43d169d70bSTobias Grosser  *
44*3f9bf9f4Spatacca  * Look through all constructors for implicit conversion constructors that take
45*3f9bf9f4Spatacca  * an isl type and add those types, along with the corresponding
46*3f9bf9f4Spatacca  * constructor argument.
47d169d70bSTobias Grosser  */
set_class_construction_types(isl_class & clazz)48*3f9bf9f4Spatacca void cpp_generator::set_class_construction_types(isl_class &clazz)
49d169d70bSTobias Grosser {
50*3f9bf9f4Spatacca 	for (const auto &cons : clazz.constructors) {
51*3f9bf9f4Spatacca 		ParmVarDecl *param;
52*3f9bf9f4Spatacca 		QualType type;
53*3f9bf9f4Spatacca 		std::string arg_type;
54d169d70bSTobias Grosser 
55*3f9bf9f4Spatacca 		if (!is_implicit_conversion(Method(clazz, cons)))
56*3f9bf9f4Spatacca 			continue;
57*3f9bf9f4Spatacca 
58*3f9bf9f4Spatacca 		param = cons->getParamDecl(0);
59*3f9bf9f4Spatacca 		type = param->getOriginalType();
60*3f9bf9f4Spatacca 		arg_type = extract_type(type);
61*3f9bf9f4Spatacca 		clazz.construction_types.emplace(arg_type, param);
62*3f9bf9f4Spatacca 	}
63d169d70bSTobias Grosser }
64d169d70bSTobias Grosser 
65*3f9bf9f4Spatacca /* Determine the isl types from which any (proper) class can be constructed
66*3f9bf9f4Spatacca  * using a unary constructor.
67*3f9bf9f4Spatacca  */
set_construction_types()68*3f9bf9f4Spatacca void cpp_generator::set_construction_types()
69*3f9bf9f4Spatacca {
70*3f9bf9f4Spatacca 	for (auto &kvp : classes) {
71*3f9bf9f4Spatacca 		auto &clazz = kvp.second;
72*3f9bf9f4Spatacca 		set_class_construction_types(clazz);
73*3f9bf9f4Spatacca 	}
74*3f9bf9f4Spatacca }
75*3f9bf9f4Spatacca 
76*3f9bf9f4Spatacca /* Construct a generator for C++ bindings.
77e8227804SMichael Kruse  *
78*3f9bf9f4Spatacca  * The classes and methods are extracted by the constructor
79*3f9bf9f4Spatacca  * of the generator superclass.
80e8227804SMichael Kruse  *
81*3f9bf9f4Spatacca  * Additionally extract information about types
82*3f9bf9f4Spatacca  * that can be converted to a class and copy all methods
83*3f9bf9f4Spatacca  * from superclasses that can be converted to a given class
84*3f9bf9f4Spatacca  * to that class.
85e8227804SMichael Kruse  */
cpp_generator(SourceManager & SM,set<RecordDecl * > & exported_types,set<FunctionDecl * > exported_functions,set<FunctionDecl * > functions)86*3f9bf9f4Spatacca cpp_generator::cpp_generator(SourceManager &SM,
87*3f9bf9f4Spatacca 	set<RecordDecl *> &exported_types,
88*3f9bf9f4Spatacca 	set<FunctionDecl *> exported_functions, set<FunctionDecl *> functions) :
89*3f9bf9f4Spatacca 		generator(SM, exported_types, exported_functions, functions)
90e8227804SMichael Kruse {
91*3f9bf9f4Spatacca 	set_construction_types();
92*3f9bf9f4Spatacca 	copy_super_methods();
93e8227804SMichael Kruse }
94e8227804SMichael Kruse 
95*3f9bf9f4Spatacca /* Copy the method called "name" described by "fd" from "super" to "clazz"
96*3f9bf9f4Spatacca  * with the distance to the original ancestor given by "depth".
97d169d70bSTobias Grosser  *
98*3f9bf9f4Spatacca  * In particular, keep track of "fd" as well as the superclass
99*3f9bf9f4Spatacca  * from which it was copied and the distance to the original ancestor.
100d169d70bSTobias Grosser  */
copy_method(isl_class & clazz,const isl_class & super,const std::string & name,FunctionDecl * fd,int depth)101*3f9bf9f4Spatacca static void copy_method(isl_class &clazz, const isl_class &super,
102*3f9bf9f4Spatacca 	const std::string &name, FunctionDecl *fd, int depth)
103d169d70bSTobias Grosser {
104*3f9bf9f4Spatacca 	clazz.methods[name].insert(fd);
105*3f9bf9f4Spatacca 	clazz.copied_from.emplace(fd, super);
106*3f9bf9f4Spatacca 	clazz.copy_depth.emplace(fd, depth);
107d169d70bSTobias Grosser }
108d169d70bSTobias Grosser 
109*3f9bf9f4Spatacca /* Do "fd1" and "fd2" have the same signature (ignoring the first argument
110*3f9bf9f4Spatacca  * which represents the object class on which the corresponding method
111*3f9bf9f4Spatacca  * gets called).
112d169d70bSTobias Grosser  */
same_signature(FunctionDecl * fd1,FunctionDecl * fd2)113*3f9bf9f4Spatacca static bool same_signature(FunctionDecl *fd1, FunctionDecl *fd2)
114d169d70bSTobias Grosser {
115*3f9bf9f4Spatacca 	int n1 = fd1->getNumParams();
116*3f9bf9f4Spatacca 	int n2 = fd2->getNumParams();
117d169d70bSTobias Grosser 
118*3f9bf9f4Spatacca 	if (n1 != n2)
119*3f9bf9f4Spatacca 		return false;
120d169d70bSTobias Grosser 
121*3f9bf9f4Spatacca 	for (int i = 1; i < n1; ++i) {
122*3f9bf9f4Spatacca 		ParmVarDecl *p1 = fd1->getParamDecl(i);
123*3f9bf9f4Spatacca 		ParmVarDecl *p2 = fd2->getParamDecl(i);
124*3f9bf9f4Spatacca 
125*3f9bf9f4Spatacca 		if (p1->getOriginalType() != p2->getOriginalType())
126*3f9bf9f4Spatacca 			return false;
127d169d70bSTobias Grosser 	}
128d169d70bSTobias Grosser 
129*3f9bf9f4Spatacca 	return true;
130*3f9bf9f4Spatacca }
131*3f9bf9f4Spatacca 
132*3f9bf9f4Spatacca /* Return the distance between "clazz" and the ancestor
133*3f9bf9f4Spatacca  * from which "fd" got copied.
134*3f9bf9f4Spatacca  * If no distance was recorded, then the method has not been copied
135*3f9bf9f4Spatacca  * but appears in "clazz" itself and so the distance is zero.
136d169d70bSTobias Grosser  */
copy_depth(const isl_class & clazz,FunctionDecl * fd)137*3f9bf9f4Spatacca static int copy_depth(const isl_class &clazz, FunctionDecl *fd)
138d169d70bSTobias Grosser {
139*3f9bf9f4Spatacca 	if (clazz.copy_depth.count(fd) == 0)
140*3f9bf9f4Spatacca 		return 0;
141*3f9bf9f4Spatacca 	return clazz.copy_depth.at(fd);
142d169d70bSTobias Grosser }
143d169d70bSTobias Grosser 
144*3f9bf9f4Spatacca /* Is the method derived from "fd", with method name "name" and
145*3f9bf9f4Spatacca  * with distance to the original ancestor "depth",
146*3f9bf9f4Spatacca  * overridden by a method already in "clazz"?
147*3f9bf9f4Spatacca  *
148*3f9bf9f4Spatacca  * A method is considered to have been overridden if there
149*3f9bf9f4Spatacca  * is a method with the same name in "clazz" that has the same signature and
150*3f9bf9f4Spatacca  * that comes from an ancestor closer to "clazz",
151*3f9bf9f4Spatacca  * where an ancestor is closer if the distance in the class hierarchy
152*3f9bf9f4Spatacca  * is smaller or the distance is the same and the ancestor appears
153*3f9bf9f4Spatacca  * closer in the declaration of the type (in which case it gets added first).
154*3f9bf9f4Spatacca  *
155*3f9bf9f4Spatacca  * If a method with the same signature has already been added,
156*3f9bf9f4Spatacca  * but it does not override the method derived from "fd",
157*3f9bf9f4Spatacca  * then this method is removed since it is overridden by "fd".
158d169d70bSTobias Grosser  */
is_overridden(FunctionDecl * fd,isl_class & clazz,const std::string & name,int depth)159*3f9bf9f4Spatacca static bool is_overridden(FunctionDecl *fd, isl_class &clazz,
160*3f9bf9f4Spatacca 	const std::string &name, int depth)
161d169d70bSTobias Grosser {
162*3f9bf9f4Spatacca 	if (clazz.methods.count(name) == 0)
163*3f9bf9f4Spatacca 		return false;
164d169d70bSTobias Grosser 
165*3f9bf9f4Spatacca 	for (const auto &m : clazz.methods.at(name)) {
166*3f9bf9f4Spatacca 		if (!same_signature(fd, m))
167*3f9bf9f4Spatacca 			continue;
168*3f9bf9f4Spatacca 		if (copy_depth(clazz, m) <= depth)
169*3f9bf9f4Spatacca 			return true;
170*3f9bf9f4Spatacca 		clazz.methods[name].erase(m);
171*3f9bf9f4Spatacca 		return false;
172d169d70bSTobias Grosser 	}
173*3f9bf9f4Spatacca 	return false;
174d169d70bSTobias Grosser }
175d169d70bSTobias Grosser 
176*3f9bf9f4Spatacca /* Add the methods "methods" with method name "name" from "super" to "clazz"
177*3f9bf9f4Spatacca  * provided they have not been overridden by a method already in "clazz".
178*3f9bf9f4Spatacca  *
179*3f9bf9f4Spatacca  * Methods that are static in their original class are not copied.
180e8227804SMichael Kruse  */
copy_methods(isl_class & clazz,const std::string & name,const isl_class & super,const function_set & methods)181*3f9bf9f4Spatacca void cpp_generator::copy_methods(isl_class &clazz, const std::string &name,
182*3f9bf9f4Spatacca 	const isl_class &super, const function_set &methods)
183e8227804SMichael Kruse {
184*3f9bf9f4Spatacca 	for (auto fd : methods) {
185*3f9bf9f4Spatacca 		int depth;
186e8227804SMichael Kruse 
187*3f9bf9f4Spatacca 		if (method2class(fd)->is_static(fd))
188*3f9bf9f4Spatacca 			continue;
189*3f9bf9f4Spatacca 		depth = copy_depth(super, fd) + 1;
190*3f9bf9f4Spatacca 		if (is_overridden(fd, clazz, name, depth))
191*3f9bf9f4Spatacca 			continue;
192*3f9bf9f4Spatacca 		copy_method(clazz, super, name, fd, depth);
193*3f9bf9f4Spatacca 	}
194e8227804SMichael Kruse }
195e8227804SMichael Kruse 
196*3f9bf9f4Spatacca /* Add all methods from "super" to "clazz" that have not been overridden
197*3f9bf9f4Spatacca  * by a method already in "clazz".
198e8227804SMichael Kruse  *
199*3f9bf9f4Spatacca  * Look through all groups of methods with the same name.
200d169d70bSTobias Grosser  */
copy_super_methods(isl_class & clazz,const isl_class & super)201*3f9bf9f4Spatacca void cpp_generator::copy_super_methods(isl_class &clazz, const isl_class &super)
202d169d70bSTobias Grosser {
203*3f9bf9f4Spatacca 	for (const auto &kvp : super.methods) {
204*3f9bf9f4Spatacca 		const auto &name = kvp.first;
205*3f9bf9f4Spatacca 		const auto &methods = kvp.second;
206d169d70bSTobias Grosser 
207*3f9bf9f4Spatacca 		copy_methods(clazz, name, super, methods);
208e8227804SMichael Kruse 	}
209d169d70bSTobias Grosser }
210d169d70bSTobias Grosser 
211*3f9bf9f4Spatacca /* Copy methods from the superclasses of "clazz"
212*3f9bf9f4Spatacca  * if an object of this class can be implicitly converted to an object
213*3f9bf9f4Spatacca  * from the superclass, keeping track
214*3f9bf9f4Spatacca  * of the classes that have already been handled in "done".
215*3f9bf9f4Spatacca  *
216*3f9bf9f4Spatacca  * Make sure the superclasses have copied methods from their superclasses first
217*3f9bf9f4Spatacca  * since those methods could be copied further down to this class.
218*3f9bf9f4Spatacca  *
219*3f9bf9f4Spatacca  * Consider the superclass that appears closest to the subclass first.
220d169d70bSTobias Grosser  */
copy_super_methods(isl_class & clazz,set<string> & done)221*3f9bf9f4Spatacca void cpp_generator::copy_super_methods(isl_class &clazz, set<string> &done)
222d169d70bSTobias Grosser {
223*3f9bf9f4Spatacca 	auto supers = find_superclasses(clazz.type);
224d169d70bSTobias Grosser 
225*3f9bf9f4Spatacca 	for (const auto &super : supers)
226*3f9bf9f4Spatacca 		if (done.count(super) == 0)
227*3f9bf9f4Spatacca 			copy_super_methods(classes[super], done);
228*3f9bf9f4Spatacca 	done.insert(clazz.name);
229*3f9bf9f4Spatacca 
230*3f9bf9f4Spatacca 	for (const auto &super_name : supers) {
231*3f9bf9f4Spatacca 		const auto &super = classes[super_name];
232*3f9bf9f4Spatacca 
233*3f9bf9f4Spatacca 		if (super.construction_types.count(clazz.name) == 0)
234*3f9bf9f4Spatacca 			continue;
235*3f9bf9f4Spatacca 		copy_super_methods(clazz, super);
236*3f9bf9f4Spatacca 	}
237d169d70bSTobias Grosser }
238d169d70bSTobias Grosser 
239*3f9bf9f4Spatacca /* For each (proper) class, copy methods from its superclasses,
240*3f9bf9f4Spatacca  * if an object from the class can be converted to an object
241*3f9bf9f4Spatacca  * from the superclass.
242d169d70bSTobias Grosser  *
243*3f9bf9f4Spatacca  * Type based subclasses are not considered for now since
244*3f9bf9f4Spatacca  * they do not have any explicit superclasses.
245d169d70bSTobias Grosser  *
246*3f9bf9f4Spatacca  * Iterate through all (proper) classes and copy methods
247*3f9bf9f4Spatacca  * from their superclasses,
248*3f9bf9f4Spatacca  * unless they have already been determined by a recursive call.
249d169d70bSTobias Grosser  */
copy_super_methods()250*3f9bf9f4Spatacca void cpp_generator::copy_super_methods()
251d169d70bSTobias Grosser {
252*3f9bf9f4Spatacca 	set<string> done;
253*3f9bf9f4Spatacca 
254*3f9bf9f4Spatacca 	for (auto &kvp : classes) {
255*3f9bf9f4Spatacca 		auto &clazz = kvp.second;
256d169d70bSTobias Grosser 
257e8227804SMichael Kruse 		if (clazz.is_type_subclass())
258*3f9bf9f4Spatacca 			continue;
259*3f9bf9f4Spatacca 		if (done.count(clazz.name) != 0)
260*3f9bf9f4Spatacca 			continue;
261*3f9bf9f4Spatacca 		copy_super_methods(clazz, done);
262*3f9bf9f4Spatacca 	}
263d169d70bSTobias Grosser }
264d169d70bSTobias Grosser 
265*3f9bf9f4Spatacca /* Print declarations or implementations of constructors.
266d169d70bSTobias Grosser  *
267d169d70bSTobias Grosser  * For each isl function that is marked as __isl_constructor,
268d169d70bSTobias Grosser  * add a corresponding C++ constructor.
269d169d70bSTobias Grosser  *
270*3f9bf9f4Spatacca  * Example of declarations:
271d169d70bSTobias Grosser  *
272d169d70bSTobias Grosser  * 	inline /\* implicit *\/ union_set(basic_set bset);
273d169d70bSTobias Grosser  * 	inline /\* implicit *\/ union_set(set set);
274d169d70bSTobias Grosser  * 	inline explicit val(ctx ctx, long i);
275d169d70bSTobias Grosser  * 	inline explicit val(ctx ctx, const std::string &str);
276d169d70bSTobias Grosser  */
print_constructors()277*3f9bf9f4Spatacca void cpp_generator::class_printer::print_constructors()
278d169d70bSTobias Grosser {
279*3f9bf9f4Spatacca 	for (const auto &cons : clazz.constructors)
280*3f9bf9f4Spatacca 		print_method(Method(clazz, cons));
281d169d70bSTobias Grosser }
282d169d70bSTobias Grosser 
283*3f9bf9f4Spatacca /* Print declarations or definitions for methods in the class.
284d169d70bSTobias Grosser  */
print_methods()285*3f9bf9f4Spatacca void cpp_generator::class_printer::print_methods()
286d169d70bSTobias Grosser {
287*3f9bf9f4Spatacca 	for (const auto &kvp : clazz.methods)
288*3f9bf9f4Spatacca 		print_method_group(kvp.second, kvp.first);
289d169d70bSTobias Grosser }
290d169d70bSTobias Grosser 
291*3f9bf9f4Spatacca /* Print declarations or implementations for the methods derived from "fd",
292*3f9bf9f4Spatacca  * which sets an enum.
293e8227804SMichael Kruse  *
294e8227804SMichael Kruse  * A method is generated for each value in the enum, setting
295e8227804SMichael Kruse  * the enum to that value.
296e8227804SMichael Kruse  */
print_set_enums(FunctionDecl * fd)297*3f9bf9f4Spatacca void cpp_generator::class_printer::print_set_enums(FunctionDecl *fd)
298e8227804SMichael Kruse {
299*3f9bf9f4Spatacca 	for (const auto &set : clazz.set_enums.at(fd)) {
300*3f9bf9f4Spatacca 		EnumMethod method(clazz, fd, set.method_name, set.name);
301e8227804SMichael Kruse 
302*3f9bf9f4Spatacca 		print_method(method);
303*3f9bf9f4Spatacca 	}
304e8227804SMichael Kruse }
305e8227804SMichael Kruse 
306*3f9bf9f4Spatacca /* Print declarations or implementations for methods derived from functions
307*3f9bf9f4Spatacca  * that set an enum.
308e8227804SMichael Kruse  */
print_set_enums()309*3f9bf9f4Spatacca void cpp_generator::class_printer::print_set_enums()
310e8227804SMichael Kruse {
311*3f9bf9f4Spatacca 	for (const auto &kvp : clazz.set_enums)
312*3f9bf9f4Spatacca 		print_set_enums(kvp.first);
313e8227804SMichael Kruse }
314e8227804SMichael Kruse 
315e8227804SMichael Kruse /* Update "convert" to reflect the next combination of automatic conversions
316e8227804SMichael Kruse  * for the arguments of "fd",
317e8227804SMichael Kruse  * returning false if there are no more combinations.
318e8227804SMichael Kruse  *
319e8227804SMichael Kruse  * In particular, find the last argument for which an automatic
320e8227804SMichael Kruse  * conversion function is available mapping to the type of this argument and
321e8227804SMichael Kruse  * that is not already marked for conversion.
322e8227804SMichael Kruse  * Mark this argument, if any, for conversion and clear the markings
323e8227804SMichael Kruse  * of all subsequent arguments.
324e8227804SMichael Kruse  * Repeated calls to this method therefore run through
325e8227804SMichael Kruse  * all possible combinations.
326e8227804SMichael Kruse  *
327e8227804SMichael Kruse  * Note that the first function argument is never considered
328e8227804SMichael Kruse  * for automatic conversion since this is the argument
329e8227804SMichael Kruse  * from which the isl_ctx used in the conversion is extracted.
330e8227804SMichael Kruse  */
next_variant(FunctionDecl * fd,std::vector<bool> & convert)331*3f9bf9f4Spatacca bool cpp_generator::class_printer::next_variant(FunctionDecl *fd,
332*3f9bf9f4Spatacca 	std::vector<bool> &convert)
333e8227804SMichael Kruse {
334e8227804SMichael Kruse 	size_t n = convert.size();
335e8227804SMichael Kruse 
336e8227804SMichael Kruse 	for (int i = n - 1; i >= 1; --i) {
337e8227804SMichael Kruse 		ParmVarDecl *param = fd->getParamDecl(i);
338e8227804SMichael Kruse 		const Type *type = param->getOriginalType().getTypePtr();
339e8227804SMichael Kruse 
340*3f9bf9f4Spatacca 		if (generator.conversions.count(type) == 0)
341e8227804SMichael Kruse 			continue;
342e8227804SMichael Kruse 		if (convert[i])
343e8227804SMichael Kruse 			continue;
344e8227804SMichael Kruse 		convert[i] = true;
345e8227804SMichael Kruse 		for (size_t j = i + 1; j < n; ++j)
346e8227804SMichael Kruse 			convert[j] = false;
347e8227804SMichael Kruse 		return true;
348e8227804SMichael Kruse 	}
349e8227804SMichael Kruse 
350e8227804SMichael Kruse 	return false;
351e8227804SMichael Kruse }
352e8227804SMichael Kruse 
353*3f9bf9f4Spatacca /* Print a declaration or definition for a method called "name"
354*3f9bf9f4Spatacca  * derived from "fd".
355e8227804SMichael Kruse  *
356*3f9bf9f4Spatacca  * If the method was copied from a superclass, then print a definition
357*3f9bf9f4Spatacca  * that calls the corresponding method in the superclass.
358*3f9bf9f4Spatacca  * Otherwise, for methods that are identified as "get" methods, also
359e8227804SMichael Kruse  * print a declaration or definition for the method
360e8227804SMichael Kruse  * using a name that includes the "get_" prefix.
361e8227804SMichael Kruse  *
362e8227804SMichael Kruse  * If the generated method is an object method, then check
363e8227804SMichael Kruse  * whether any of its arguments can be automatically converted
364e8227804SMichael Kruse  * from something else, and, if so, generate a method
365e8227804SMichael Kruse  * for each combination of converted arguments.
366*3f9bf9f4Spatacca  * Do so by constructing a ConversionMethod that changes the converted arguments
367*3f9bf9f4Spatacca  * to those of the sources of the conversions.
368*3f9bf9f4Spatacca  *
369*3f9bf9f4Spatacca  * Note that a method may be both copied from a superclass and
370*3f9bf9f4Spatacca  * have arguments that can be automatically converted.
371*3f9bf9f4Spatacca  * In this case, the conversion methods for the arguments
372*3f9bf9f4Spatacca  * call the corresponding method in this class, which
373*3f9bf9f4Spatacca  * in turn will call the method in the superclass.
374e8227804SMichael Kruse  */
print_method_variants(FunctionDecl * fd,const std::string & name)375*3f9bf9f4Spatacca void cpp_generator::class_printer::print_method_variants(FunctionDecl *fd,
376*3f9bf9f4Spatacca 	const std::string &name)
377e8227804SMichael Kruse {
378*3f9bf9f4Spatacca 	Method method(clazz, fd, name);
379*3f9bf9f4Spatacca 	std::vector<bool> convert(method.num_params());
380e8227804SMichael Kruse 
381*3f9bf9f4Spatacca 	if (method.clazz.copied_from.count(method.fd) == 0) {
382*3f9bf9f4Spatacca 		print_method(method);
383e8227804SMichael Kruse 		if (clazz.is_get_method(fd))
384*3f9bf9f4Spatacca 			print_get_method(fd);
385*3f9bf9f4Spatacca 	} else {
386*3f9bf9f4Spatacca 		auto super = method.clazz.copied_from.at(method.fd);
387*3f9bf9f4Spatacca 		print_method(ConversionMethod(method, super.name));
388*3f9bf9f4Spatacca 	}
389*3f9bf9f4Spatacca 	if (method.kind != Method::Kind::member_method)
390*3f9bf9f4Spatacca 		return;
391*3f9bf9f4Spatacca 	while (next_variant(fd, convert)) {
392*3f9bf9f4Spatacca 		print_method(ConversionMethod(method, [&] (int pos) {
393*3f9bf9f4Spatacca 			return get_param(fd, pos, convert);
394*3f9bf9f4Spatacca 		}));
395*3f9bf9f4Spatacca 	}
396e8227804SMichael Kruse }
397e8227804SMichael Kruse 
398*3f9bf9f4Spatacca /* Given a function declaration representing a method,
399*3f9bf9f4Spatacca  * does this method have a single argument (beyond the object
400*3f9bf9f4Spatacca  * on which the method is called) that corresponds to
401*3f9bf9f4Spatacca  * an isl object?
402d169d70bSTobias Grosser  */
has_single_isl_argument(FunctionDecl * fd)403*3f9bf9f4Spatacca static bool has_single_isl_argument(FunctionDecl *fd)
404*3f9bf9f4Spatacca {
405*3f9bf9f4Spatacca 	ParmVarDecl *param;
406*3f9bf9f4Spatacca 
407*3f9bf9f4Spatacca 	if (fd->getNumParams() != 2)
408*3f9bf9f4Spatacca 		return false;
409*3f9bf9f4Spatacca 
410*3f9bf9f4Spatacca 	param = fd->getParamDecl(1);
411*3f9bf9f4Spatacca 	return generator::is_isl_type(param->getOriginalType());
412*3f9bf9f4Spatacca }
413*3f9bf9f4Spatacca 
414*3f9bf9f4Spatacca /* Does the set "methods" contain exactly one function declaration
415*3f9bf9f4Spatacca  * that corresponds to a method of "clazz" itself (i.e., that
416*3f9bf9f4Spatacca  * was not copied from an ancestor)?
417*3f9bf9f4Spatacca  */
single_local(const isl_class & clazz,const function_set & methods)418*3f9bf9f4Spatacca static FunctionDecl *single_local(const isl_class &clazz,
419e8227804SMichael Kruse 	const function_set &methods)
420d169d70bSTobias Grosser {
421*3f9bf9f4Spatacca 	int count = 0;
422*3f9bf9f4Spatacca 	FunctionDecl *local;
423d169d70bSTobias Grosser 
424*3f9bf9f4Spatacca 	for (const auto &fn : methods) {
425*3f9bf9f4Spatacca 		if (!clazz.first_arg_matches_class(fn))
426*3f9bf9f4Spatacca 			continue;
427*3f9bf9f4Spatacca 		++count;
428*3f9bf9f4Spatacca 		local = fn;
429d169d70bSTobias Grosser 	}
430d169d70bSTobias Grosser 
431*3f9bf9f4Spatacca 	return count == 1 ? local : NULL;
432*3f9bf9f4Spatacca }
433*3f9bf9f4Spatacca 
434*3f9bf9f4Spatacca /* Given a function declaration "fd" for a method called "name"
435*3f9bf9f4Spatacca  * with a single argument representing an isl object,
436*3f9bf9f4Spatacca  * generate declarations or definitions for methods with the same name,
437*3f9bf9f4Spatacca  * but with as argument an isl object of a class that can be implicitly
438*3f9bf9f4Spatacca  * converted to that of the original argument.
439*3f9bf9f4Spatacca  * In particular, generate methods for converting this argument.
440d169d70bSTobias Grosser  */
print_descendent_overloads(FunctionDecl * fd,const std::string & name)441*3f9bf9f4Spatacca void cpp_generator::class_printer::print_descendent_overloads(
442*3f9bf9f4Spatacca 	FunctionDecl *fd, const std::string &name)
443d169d70bSTobias Grosser {
444*3f9bf9f4Spatacca 	Method method(clazz, fd, name);
445*3f9bf9f4Spatacca 	ParmVarDecl *param = fd->getParamDecl(1);
446e8227804SMichael Kruse 	QualType type = param->getOriginalType();
447*3f9bf9f4Spatacca 	std::string arg = type->getPointeeType().getAsString();
448d169d70bSTobias Grosser 
449*3f9bf9f4Spatacca 	for (const auto &kvp : generator.classes[arg].construction_types) {
450*3f9bf9f4Spatacca 		const auto sub = kvp.second;
451*3f9bf9f4Spatacca 		print_method(ConversionMethod(method, [&] (int pos) {
452*3f9bf9f4Spatacca 			return sub;
453*3f9bf9f4Spatacca 		}));
454d169d70bSTobias Grosser 	}
455d169d70bSTobias Grosser }
456d169d70bSTobias Grosser 
457*3f9bf9f4Spatacca /* Print declarations or definitions for methods called "name"
458*3f9bf9f4Spatacca  * derived from "methods".
459e8227804SMichael Kruse  *
460*3f9bf9f4Spatacca  * If want_descendent_overloads signals that variants should be added that take
461*3f9bf9f4Spatacca  * as arguments those types that can be converted to the original argument type
462*3f9bf9f4Spatacca  * through a unary constructor and if only one of the methods in the group
463*3f9bf9f4Spatacca  * was originally defined in "clazz", then effectively add those variants.
464*3f9bf9f4Spatacca  * Only do this for methods with a single (isl object) argument.
465d169d70bSTobias Grosser  */
print_method_group(const function_set & methods,const std::string & name)466*3f9bf9f4Spatacca void cpp_generator::class_printer::print_method_group(
467*3f9bf9f4Spatacca 	const function_set &methods, const std::string &name)
468d169d70bSTobias Grosser {
469*3f9bf9f4Spatacca 	FunctionDecl *local;
470d169d70bSTobias Grosser 
471*3f9bf9f4Spatacca 	for (const auto &fd : methods)
472*3f9bf9f4Spatacca 		print_method_variants(fd, name);
473*3f9bf9f4Spatacca 	if (!want_descendent_overloads(methods))
474e8227804SMichael Kruse 		return;
475*3f9bf9f4Spatacca 	local = single_local(clazz, methods);
476*3f9bf9f4Spatacca 	if (!local)
477e8227804SMichael Kruse 		return;
478*3f9bf9f4Spatacca 	if (!has_single_isl_argument(local))
479e8227804SMichael Kruse 		return;
480*3f9bf9f4Spatacca 	print_descendent_overloads(local, name);
481e8227804SMichael Kruse }
482e8227804SMichael Kruse 
483*3f9bf9f4Spatacca /* Print the use of the argument at position "pos" to "os".
484e8227804SMichael Kruse  *
485*3f9bf9f4Spatacca  * Member methods pass the isl object corresponding to "this"
486*3f9bf9f4Spatacca  * as first argument (at position 0).
487*3f9bf9f4Spatacca  * Any other arguments are passed along from the method arguments.
488e8227804SMichael Kruse  *
489*3f9bf9f4Spatacca  * If the argument value is loaded from a this pointer, the original
490d169d70bSTobias Grosser  * value must be preserved and must consequently be copied.  Values that are
491*3f9bf9f4Spatacca  * loaded from method parameters do not need to be preserved, as such values
492*3f9bf9f4Spatacca  * will already be copies of the actual parameters.  It is consequently possible
493d169d70bSTobias Grosser  * to directly take the pointer from these values, which saves
494d169d70bSTobias Grosser  * an unnecessary copy.
495d169d70bSTobias Grosser  *
496d169d70bSTobias Grosser  * In case the parameter is a callback function, two parameters get printed,
497d169d70bSTobias Grosser  * a wrapper for the callback function and a pointer to the actual
498d169d70bSTobias Grosser  * callback function.  The wrapper is expected to be available
499d169d70bSTobias Grosser  * in a previously declared variable <name>_lambda, while
500d169d70bSTobias Grosser  * the actual callback function is expected to be stored
501d169d70bSTobias Grosser  * in a structure called <name>_data.
502d169d70bSTobias Grosser  * The caller of this function must ensure that these variables exist.
503d169d70bSTobias Grosser  */
print_param_use(ostream & os,int pos) const504*3f9bf9f4Spatacca void Method::print_param_use(ostream &os, int pos) const
505d169d70bSTobias Grosser {
506*3f9bf9f4Spatacca 	ParmVarDecl *param = fd->getParamDecl(pos);
507*3f9bf9f4Spatacca 	bool load_from_this_ptr = pos == 0 && kind == member_method;
508d169d70bSTobias Grosser 	string name = param->getName().str();
509d169d70bSTobias Grosser 	QualType type = param->getOriginalType();
510d169d70bSTobias Grosser 
511d169d70bSTobias Grosser 	if (type->isIntegerType()) {
512*3f9bf9f4Spatacca 		os << name;
513d169d70bSTobias Grosser 		return;
514d169d70bSTobias Grosser 	}
515d169d70bSTobias Grosser 
516*3f9bf9f4Spatacca 	if (generator::is_string(type)) {
517*3f9bf9f4Spatacca 		os << name << ".c_str()";
518d169d70bSTobias Grosser 		return;
519d169d70bSTobias Grosser 	}
520d169d70bSTobias Grosser 
521*3f9bf9f4Spatacca 	if (generator::is_callback(type)) {
522*3f9bf9f4Spatacca 		os << name << "_lambda, ";
523*3f9bf9f4Spatacca 		os << "&" << name << "_data";
524d169d70bSTobias Grosser 		return;
525d169d70bSTobias Grosser 	}
526d169d70bSTobias Grosser 
527e8227804SMichael Kruse 	if (!load_from_this_ptr)
528*3f9bf9f4Spatacca 		os << name << ".";
529d169d70bSTobias Grosser 
530*3f9bf9f4Spatacca 	if (generator::keeps(param)) {
531*3f9bf9f4Spatacca 		os << "get()";
532d169d70bSTobias Grosser 	} else {
533d169d70bSTobias Grosser 		if (load_from_this_ptr)
534*3f9bf9f4Spatacca 			os << "copy()";
535d169d70bSTobias Grosser 		else
536*3f9bf9f4Spatacca 			os << "release()";
537d169d70bSTobias Grosser 	}
538d169d70bSTobias Grosser }
539d169d70bSTobias Grosser 
540*3f9bf9f4Spatacca /* Does the isl function from which this method is derived
541*3f9bf9f4Spatacca  * modify an object of a subclass based on a type function?
542d169d70bSTobias Grosser  */
is_subclass_mutator() const543*3f9bf9f4Spatacca bool Method::is_subclass_mutator() const
544e8227804SMichael Kruse {
545e8227804SMichael Kruse 	return clazz.is_type_subclass() && generator::is_mutator(clazz, fd);
546e8227804SMichael Kruse }
547e8227804SMichael Kruse 
548*3f9bf9f4Spatacca /* Return the C++ return type of the method "method".
549e8227804SMichael Kruse  *
550*3f9bf9f4Spatacca  * If the corresponding function modifies an object of a subclass, then return
551e8227804SMichael Kruse  * the type of this subclass.
552e8227804SMichael Kruse  * Otherwise, return the C++ counterpart of the actual return type.
553e8227804SMichael Kruse  */
return_type(const Method & method) const554*3f9bf9f4Spatacca std::string cpp_type_printer::return_type(const Method &method) const
555e8227804SMichael Kruse {
556*3f9bf9f4Spatacca 	if (method.is_subclass_mutator())
557*3f9bf9f4Spatacca 		return cpp_generator::type2cpp(method.clazz);
558e8227804SMichael Kruse 	else
559*3f9bf9f4Spatacca 		return param(-1, method.fd->getReturnType());
56026269d34STobias Grosser }
56126269d34STobias Grosser 
562e8227804SMichael Kruse /* Return the formal parameter at position "pos" of "fd".
563e8227804SMichael Kruse  * However, if this parameter should be converted, as indicated
564e8227804SMichael Kruse  * by "convert", then return the second formal parameter
565e8227804SMichael Kruse  * of the conversion function instead.
566d169d70bSTobias Grosser  */
get_param(FunctionDecl * fd,int pos,const std::vector<bool> & convert)567*3f9bf9f4Spatacca ParmVarDecl *cpp_generator::class_printer::get_param(FunctionDecl *fd,
568*3f9bf9f4Spatacca 	int pos, const std::vector<bool> &convert)
569d169d70bSTobias Grosser {
570e8227804SMichael Kruse 	ParmVarDecl *param = fd->getParamDecl(pos);
571d169d70bSTobias Grosser 
572e8227804SMichael Kruse 	if (!convert[pos])
573e8227804SMichael Kruse 		return param;
574*3f9bf9f4Spatacca 	return generator.conversions[param->getOriginalType().getTypePtr()];
575d169d70bSTobias Grosser }
576d169d70bSTobias Grosser 
577*3f9bf9f4Spatacca /* Print the header for "method", without newline or semicolon,
578*3f9bf9f4Spatacca  * using "type_printer" to print argument and return types.
579d169d70bSTobias Grosser  *
580*3f9bf9f4Spatacca  * Print the header of a declaration if this->declarations is set,
581*3f9bf9f4Spatacca  * otherwise print the header of a method definition.
582e8227804SMichael Kruse  *
583d169d70bSTobias Grosser  * This function prints headers for member methods, static methods, and
584d169d70bSTobias Grosser  * constructors, either for their declaration or definition.
585d169d70bSTobias Grosser  *
586d169d70bSTobias Grosser  * Member functions are declared as "const", as they do not change the current
587d169d70bSTobias Grosser  * object, but instead create a new object. They always retrieve the first
588d169d70bSTobias Grosser  * parameter of the original isl function from the this-pointer of the object,
589d169d70bSTobias Grosser  * such that only starting at the second parameter the parameters of the
590d169d70bSTobias Grosser  * original function become part of the method's interface.
591d169d70bSTobias Grosser  *
592d169d70bSTobias Grosser  * A function
593d169d70bSTobias Grosser  *
594d169d70bSTobias Grosser  * 	__isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
595d169d70bSTobias Grosser  * 		__isl_take isl_set *s2);
596d169d70bSTobias Grosser  *
597d169d70bSTobias Grosser  * is translated into:
598d169d70bSTobias Grosser  *
599*3f9bf9f4Spatacca  * 	inline set intersect(set set2) const
600d169d70bSTobias Grosser  *
601d169d70bSTobias Grosser  * For static functions and constructors all parameters of the original isl
602d169d70bSTobias Grosser  * function are exposed.
603d169d70bSTobias Grosser  *
604*3f9bf9f4Spatacca  * Parameters of which no copy is required, are passed
605d169d70bSTobias Grosser  * as const reference, which allows the compiler to optimize the parameter
606d169d70bSTobias Grosser  * transfer.
607d169d70bSTobias Grosser  *
608d169d70bSTobias Grosser  * Constructors are marked as explicit using the C++ keyword 'explicit' or as
609d169d70bSTobias Grosser  * implicit using a comment in place of the explicit keyword. By annotating
610d169d70bSTobias Grosser  * implicit constructors with a comment, users of the interface are made
611d169d70bSTobias Grosser  * aware of the potential danger that implicit construction is possible
612d169d70bSTobias Grosser  * for these constructors, whereas without a comment not every user would
613d169d70bSTobias Grosser  * know that implicit construction is allowed in absence of an explicit keyword.
614e8227804SMichael Kruse  *
615*3f9bf9f4Spatacca  * Note that in case "method" is a ConversionMethod, the argument returned
616*3f9bf9f4Spatacca  * by Method::get_param may be different from the original argument.
617e8227804SMichael Kruse  * The name of the argument is, however, derived from the original
618e8227804SMichael Kruse  * function argument.
619d169d70bSTobias Grosser  */
print_method_header(const Method & method,const cpp_type_printer & type_printer)620*3f9bf9f4Spatacca void cpp_generator::class_printer::print_method_header(
621*3f9bf9f4Spatacca 	const Method &method, const cpp_type_printer &type_printer)
622d169d70bSTobias Grosser {
623*3f9bf9f4Spatacca 	string rettype_str = type_printer.return_type(method);
624d169d70bSTobias Grosser 
625*3f9bf9f4Spatacca 	if (declarations) {
626*3f9bf9f4Spatacca 		os << "  ";
627d169d70bSTobias Grosser 
628*3f9bf9f4Spatacca 		if (method.kind == Method::Kind::static_method)
629*3f9bf9f4Spatacca 			os << "static ";
630d169d70bSTobias Grosser 
631*3f9bf9f4Spatacca 		os << "inline ";
632d169d70bSTobias Grosser 
633*3f9bf9f4Spatacca 		if (method.kind == Method::Kind::constructor) {
634*3f9bf9f4Spatacca 			if (generator.is_implicit_conversion(method))
635*3f9bf9f4Spatacca 				os << "/* implicit */ ";
636d169d70bSTobias Grosser 			else
637*3f9bf9f4Spatacca 				os << "explicit ";
638d169d70bSTobias Grosser 		}
639d169d70bSTobias Grosser 	}
640d169d70bSTobias Grosser 
641*3f9bf9f4Spatacca 	if (method.kind != Method::Kind::constructor)
642*3f9bf9f4Spatacca 		os << rettype_str << " ";
643d169d70bSTobias Grosser 
644*3f9bf9f4Spatacca 	if (!declarations)
645*3f9bf9f4Spatacca 		os << type_printer.class_type(cppstring) << "::";
646d169d70bSTobias Grosser 
647*3f9bf9f4Spatacca 	if (method.kind != Method::Kind::constructor)
648*3f9bf9f4Spatacca 		os << method.name;
649d169d70bSTobias Grosser 	else
650*3f9bf9f4Spatacca 		os << cppstring;
651d169d70bSTobias Grosser 
652*3f9bf9f4Spatacca 	method.print_cpp_arg_list(os, [&] (int i) {
653*3f9bf9f4Spatacca 		std::string name = method.fd->getParamDecl(i)->getName().str();
654*3f9bf9f4Spatacca 		ParmVarDecl *param = method.get_param(i);
655d169d70bSTobias Grosser 		QualType type = param->getOriginalType();
656*3f9bf9f4Spatacca 		string cpptype = type_printer.param(i, type);
657d169d70bSTobias Grosser 
658*3f9bf9f4Spatacca 		if (!method.param_needs_copy(i))
659*3f9bf9f4Spatacca 			os << "const " << cpptype << " &" << name;
660d169d70bSTobias Grosser 		else
661*3f9bf9f4Spatacca 			os << cpptype << " " << name;
662*3f9bf9f4Spatacca 	});
663d169d70bSTobias Grosser 
664*3f9bf9f4Spatacca 	if (method.kind == Method::Kind::member_method)
665*3f9bf9f4Spatacca 		os << " const";
666e8227804SMichael Kruse }
667e8227804SMichael Kruse 
668d169d70bSTobias Grosser /* Generate the list of argument types for a callback function of
669*3f9bf9f4Spatacca  * type "type", appearing in argument position "arg".
670*3f9bf9f4Spatacca  * If "cpp" is set, then generate the C++ type list, otherwise
671d169d70bSTobias Grosser  * the C type list.
672d169d70bSTobias Grosser  *
673d169d70bSTobias Grosser  * For a callback of type
674d169d70bSTobias Grosser  *
675d169d70bSTobias Grosser  *      isl_stat (*)(__isl_take isl_map *map, void *user)
676d169d70bSTobias Grosser  *
677d169d70bSTobias Grosser  * the following C++ argument list is generated:
678d169d70bSTobias Grosser  *
679d169d70bSTobias Grosser  *      map
680*3f9bf9f4Spatacca  *
681*3f9bf9f4Spatacca  * The arguments of the callback are considered to appear
682*3f9bf9f4Spatacca  * after the position of the callback itself.
683d169d70bSTobias Grosser  */
generate_callback_args(int arg,QualType type,bool cpp) const684*3f9bf9f4Spatacca std::string cpp_type_printer::generate_callback_args(int arg, QualType type,
685*3f9bf9f4Spatacca 	bool cpp) const
686d169d70bSTobias Grosser {
687d169d70bSTobias Grosser 	std::string type_str;
688d169d70bSTobias Grosser 	const FunctionProtoType *callback;
689d169d70bSTobias Grosser 	int num_params;
690d169d70bSTobias Grosser 
691*3f9bf9f4Spatacca 	callback = generator::extract_prototype(type);
692d169d70bSTobias Grosser 	num_params = callback->getNumArgs();
693d169d70bSTobias Grosser 	if (cpp)
694d169d70bSTobias Grosser 		num_params--;
695d169d70bSTobias Grosser 
696d169d70bSTobias Grosser 	for (long i = 0; i < num_params; i++) {
697d169d70bSTobias Grosser 		QualType type = callback->getArgType(i);
698d169d70bSTobias Grosser 
699d169d70bSTobias Grosser 		if (cpp)
700*3f9bf9f4Spatacca 			type_str += param(arg + 1 + i, type);
701d169d70bSTobias Grosser 		else
702d169d70bSTobias Grosser 			type_str += type.getAsString();
703d169d70bSTobias Grosser 
704d169d70bSTobias Grosser 		if (!cpp)
705d169d70bSTobias Grosser 			type_str += "arg_" + ::to_string(i);
706d169d70bSTobias Grosser 
707d169d70bSTobias Grosser 		if (i != num_params - 1)
708d169d70bSTobias Grosser 			type_str += ", ";
709d169d70bSTobias Grosser 	}
710d169d70bSTobias Grosser 
711d169d70bSTobias Grosser 	return type_str;
712d169d70bSTobias Grosser }
713d169d70bSTobias Grosser 
714*3f9bf9f4Spatacca /* Generate the full cpp type of a callback function of type "type",
715*3f9bf9f4Spatacca  * appearing in argument position "arg".
716d169d70bSTobias Grosser  *
717d169d70bSTobias Grosser  * For a callback of type
718d169d70bSTobias Grosser  *
719d169d70bSTobias Grosser  *      isl_stat (*)(__isl_take isl_map *map, void *user)
720d169d70bSTobias Grosser  *
721d169d70bSTobias Grosser  * the following type is generated:
722d169d70bSTobias Grosser  *
723d169d70bSTobias Grosser  *      std::function<stat(map)>
724d169d70bSTobias Grosser  */
generate_callback_type(int arg,QualType type) const725*3f9bf9f4Spatacca std::string cpp_type_printer::generate_callback_type(int arg, QualType type)
726*3f9bf9f4Spatacca 	const
727d169d70bSTobias Grosser {
728d169d70bSTobias Grosser 	std::string type_str;
729*3f9bf9f4Spatacca 	const FunctionProtoType *callback = generator::extract_prototype(type);
730d169d70bSTobias Grosser 	QualType return_type = callback->getReturnType();
731*3f9bf9f4Spatacca 	string rettype_str = param(arg, return_type);
732d169d70bSTobias Grosser 
733d169d70bSTobias Grosser 	type_str = "std::function<";
734d169d70bSTobias Grosser 	type_str += rettype_str;
735d169d70bSTobias Grosser 	type_str += "(";
736*3f9bf9f4Spatacca 	type_str += generate_callback_args(arg, type, true);
737d169d70bSTobias Grosser 	type_str += ")>";
738d169d70bSTobias Grosser 
739d169d70bSTobias Grosser 	return type_str;
740d169d70bSTobias Grosser }
741d169d70bSTobias Grosser 
742d169d70bSTobias Grosser /* An array listing functions that must be renamed and the function name they
743d169d70bSTobias Grosser  * should be renamed to. We currently rename functions in case their name would
744d169d70bSTobias Grosser  * match a reserved C++ keyword, which is not allowed in C++.
745d169d70bSTobias Grosser  */
746d169d70bSTobias Grosser static const char *rename_map[][2] = {
747d169d70bSTobias Grosser 	{ "union", "unite" },
748d169d70bSTobias Grosser };
749d169d70bSTobias Grosser 
750d169d70bSTobias Grosser /* Rename method "name" in case the method name in the C++ bindings should not
751d169d70bSTobias Grosser  * match the name in the C bindings. We do this for example to avoid
752d169d70bSTobias Grosser  * C++ keywords.
753d169d70bSTobias Grosser  */
rename_method(std::string name)754*3f9bf9f4Spatacca static std::string rename_method(std::string name)
755d169d70bSTobias Grosser {
756d169d70bSTobias Grosser 	for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++)
757d169d70bSTobias Grosser 		if (name.compare(rename_map[i][0]) == 0)
758d169d70bSTobias Grosser 			return rename_map[i][1];
759d169d70bSTobias Grosser 
760d169d70bSTobias Grosser 	return name;
761d169d70bSTobias Grosser }
762d169d70bSTobias Grosser 
763d169d70bSTobias Grosser /* Translate isl class "clazz" to its corresponding C++ type.
764e8227804SMichael Kruse  * Use the name of the type based subclass, if any.
765d169d70bSTobias Grosser  */
type2cpp(const isl_class & clazz)766d169d70bSTobias Grosser string cpp_generator::type2cpp(const isl_class &clazz)
767d169d70bSTobias Grosser {
768e8227804SMichael Kruse 	return type2cpp(clazz.subclass_name);
769d169d70bSTobias Grosser }
770d169d70bSTobias Grosser 
771d169d70bSTobias Grosser /* Translate type string "type_str" to its C++ name counterpart.
772d169d70bSTobias Grosser */
type2cpp(string type_str)773d169d70bSTobias Grosser string cpp_generator::type2cpp(string type_str)
774d169d70bSTobias Grosser {
775d169d70bSTobias Grosser 	return type_str.substr(4);
776d169d70bSTobias Grosser }
777d169d70bSTobias Grosser 
778e8227804SMichael Kruse /* Return the C++ counterpart to the isl_bool type.
779*3f9bf9f4Spatacca  *
780*3f9bf9f4Spatacca  * By default, this is simply "bool" since
781*3f9bf9f4Spatacca  * the exceptional case is handled through exceptions.
782e8227804SMichael Kruse  */
isl_bool() const783*3f9bf9f4Spatacca std::string cpp_type_printer::isl_bool() const
784e8227804SMichael Kruse {
785*3f9bf9f4Spatacca 	return "bool";
786*3f9bf9f4Spatacca }
787*3f9bf9f4Spatacca 
788*3f9bf9f4Spatacca /* Return the C++ counterpart to the isl_stat type.
789*3f9bf9f4Spatacca  *
790*3f9bf9f4Spatacca  * By default, this is simply "void" since
791*3f9bf9f4Spatacca  * the exceptional case is handled through exceptions.
792*3f9bf9f4Spatacca  */
isl_stat() const793*3f9bf9f4Spatacca string cpp_type_printer::isl_stat() const
794*3f9bf9f4Spatacca {
795*3f9bf9f4Spatacca 	return "void";
796*3f9bf9f4Spatacca }
797*3f9bf9f4Spatacca 
798*3f9bf9f4Spatacca /* Return the C++ counterpart to the isl_size type.
799*3f9bf9f4Spatacca  *
800*3f9bf9f4Spatacca  * By default, this is simply "unsigned" since
801*3f9bf9f4Spatacca  * the exceptional case is handled through exceptions.
802*3f9bf9f4Spatacca  */
isl_size() const803*3f9bf9f4Spatacca string cpp_type_printer::isl_size() const
804*3f9bf9f4Spatacca {
805*3f9bf9f4Spatacca 	return "unsigned";
806e8227804SMichael Kruse }
807e8227804SMichael Kruse 
808e8227804SMichael Kruse /* Return the namespace of the generated C++ bindings.
809*3f9bf9f4Spatacca  *
810*3f9bf9f4Spatacca  * By default, this is "isl::".
811e8227804SMichael Kruse  */
isl_namespace() const812*3f9bf9f4Spatacca std::string cpp_type_printer::isl_namespace() const
813e8227804SMichael Kruse {
814*3f9bf9f4Spatacca 	return "isl::";
815e8227804SMichael Kruse }
816e8227804SMichael Kruse 
817*3f9bf9f4Spatacca /* Return the class type given the C++ name.
818d169d70bSTobias Grosser  *
819*3f9bf9f4Spatacca  * By default, directly use the C++ name.
820d169d70bSTobias Grosser  */
class_type(const std::string & cpp_name) const821*3f9bf9f4Spatacca std::string cpp_type_printer::class_type(const std::string &cpp_name) const
822d169d70bSTobias Grosser {
823*3f9bf9f4Spatacca 	return cpp_name;
824*3f9bf9f4Spatacca }
825d169d70bSTobias Grosser 
826*3f9bf9f4Spatacca /* Return the qualified form of the given C++ isl type name appearing
827*3f9bf9f4Spatacca  * in argument position "arg" (-1 for return type).
828*3f9bf9f4Spatacca  *
829*3f9bf9f4Spatacca  * By default, the argument position is ignored.
830*3f9bf9f4Spatacca  */
qualified(int arg,const std::string & cpp_type) const831*3f9bf9f4Spatacca std::string cpp_type_printer::qualified(int arg, const std::string &cpp_type)
832*3f9bf9f4Spatacca 	const
833*3f9bf9f4Spatacca {
834*3f9bf9f4Spatacca 	return isl_namespace() + cpp_type;
835*3f9bf9f4Spatacca }
836d169d70bSTobias Grosser 
837*3f9bf9f4Spatacca /* Return the C++ counterpart to the given isl type appearing
838*3f9bf9f4Spatacca  * in argument position "arg" (-1 for return type).
839*3f9bf9f4Spatacca  */
isl_type(int arg,QualType type) const840*3f9bf9f4Spatacca std::string cpp_type_printer::isl_type(int arg, QualType type) const
841*3f9bf9f4Spatacca {
842*3f9bf9f4Spatacca 	auto name = type->getPointeeType().getAsString();
843*3f9bf9f4Spatacca 	return qualified(arg, cpp_generator::type2cpp(name));
844*3f9bf9f4Spatacca }
845d169d70bSTobias Grosser 
846*3f9bf9f4Spatacca /* Translate parameter or return type "type" to its C++ name counterpart.
847*3f9bf9f4Spatacca  * "arg" is the position of the argument, or -1 in case of the return type.
848*3f9bf9f4Spatacca  * If any callback is involved, then the return type and arguments types
849*3f9bf9f4Spatacca  * of the callback are considered to start at the position of the callback.
850*3f9bf9f4Spatacca  */
param(int arg,QualType type) const851*3f9bf9f4Spatacca std::string cpp_type_printer::param(int arg, QualType type) const
852*3f9bf9f4Spatacca {
853*3f9bf9f4Spatacca 	if (cpp_generator::is_isl_type(type))
854*3f9bf9f4Spatacca 		return isl_type(arg, type);
855*3f9bf9f4Spatacca 
856*3f9bf9f4Spatacca 	if (cpp_generator::is_isl_bool(type))
857*3f9bf9f4Spatacca 		return isl_bool();
858*3f9bf9f4Spatacca 
859*3f9bf9f4Spatacca 	if (cpp_generator::is_isl_stat(type))
860*3f9bf9f4Spatacca 		return isl_stat();
861*3f9bf9f4Spatacca 
862*3f9bf9f4Spatacca 	if (cpp_generator::is_isl_size(type))
863*3f9bf9f4Spatacca 		return isl_size();
864e8227804SMichael Kruse 
865d169d70bSTobias Grosser 	if (type->isIntegerType())
866d169d70bSTobias Grosser 		return type.getAsString();
867d169d70bSTobias Grosser 
868*3f9bf9f4Spatacca 	if (cpp_generator::is_string(type))
869d169d70bSTobias Grosser 		return "std::string";
870d169d70bSTobias Grosser 
871*3f9bf9f4Spatacca 	if (cpp_generator::is_callback(type))
872*3f9bf9f4Spatacca 		return generate_callback_type(arg, type);
873d169d70bSTobias Grosser 
874*3f9bf9f4Spatacca 	generator::die("Cannot convert type to C++ type");
875d169d70bSTobias Grosser }
876d169d70bSTobias Grosser 
877d169d70bSTobias Grosser /* Check if "subclass_type" is a subclass of "class_type".
878d169d70bSTobias Grosser  */
is_subclass(QualType subclass_type,const isl_class & class_type)879d169d70bSTobias Grosser bool cpp_generator::is_subclass(QualType subclass_type,
880d169d70bSTobias Grosser 	const isl_class &class_type)
881d169d70bSTobias Grosser {
882d169d70bSTobias Grosser 	std::string type_str = subclass_type->getPointeeType().getAsString();
883d169d70bSTobias Grosser 	std::vector<std::string> superclasses;
884d169d70bSTobias Grosser 	std::vector<const isl_class *> parents;
885d169d70bSTobias Grosser 	std::vector<std::string>::iterator ci;
886d169d70bSTobias Grosser 
887d169d70bSTobias Grosser 	superclasses = generator::find_superclasses(classes[type_str].type);
888d169d70bSTobias Grosser 
889d169d70bSTobias Grosser 	for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
890d169d70bSTobias Grosser 		parents.push_back(&classes[*ci]);
891d169d70bSTobias Grosser 
892d169d70bSTobias Grosser 	while (!parents.empty()) {
893d169d70bSTobias Grosser 		const isl_class *candidate = parents.back();
894d169d70bSTobias Grosser 
895d169d70bSTobias Grosser 		parents.pop_back();
896d169d70bSTobias Grosser 
897d169d70bSTobias Grosser 		if (&class_type == candidate)
898d169d70bSTobias Grosser 			return true;
899d169d70bSTobias Grosser 
900d169d70bSTobias Grosser 		superclasses = generator::find_superclasses(candidate->type);
901d169d70bSTobias Grosser 
902d169d70bSTobias Grosser 		for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
903d169d70bSTobias Grosser 			parents.push_back(&classes[*ci]);
904d169d70bSTobias Grosser 	}
905d169d70bSTobias Grosser 
906d169d70bSTobias Grosser 	return false;
907d169d70bSTobias Grosser }
908d169d70bSTobias Grosser 
909d169d70bSTobias Grosser /* Check if "cons" is an implicit conversion constructor of class "clazz".
910d169d70bSTobias Grosser  *
911d169d70bSTobias Grosser  * An implicit conversion constructor is generated in case "cons" has a single
912d169d70bSTobias Grosser  * parameter, where the parameter type is a subclass of the class that is
913d169d70bSTobias Grosser  * currently being generated.
914d169d70bSTobias Grosser  */
is_implicit_conversion(const Method & cons)915*3f9bf9f4Spatacca bool cpp_generator::is_implicit_conversion(const Method &cons)
916d169d70bSTobias Grosser {
917*3f9bf9f4Spatacca 	const auto &clazz = cons.clazz;
918*3f9bf9f4Spatacca 	ParmVarDecl *param = cons.fd->getParamDecl(0);
919d169d70bSTobias Grosser 	QualType type = param->getOriginalType();
920d169d70bSTobias Grosser 
921*3f9bf9f4Spatacca 	int num_params = cons.fd->getNumParams();
922d169d70bSTobias Grosser 	if (num_params != 1)
923d169d70bSTobias Grosser 		return false;
924d169d70bSTobias Grosser 
925d169d70bSTobias Grosser 	if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz))
926d169d70bSTobias Grosser 		return true;
927d169d70bSTobias Grosser 
928d169d70bSTobias Grosser 	return false;
929d169d70bSTobias Grosser }
930d169d70bSTobias Grosser 
931d169d70bSTobias Grosser /* Get kind of "method" in "clazz".
932d169d70bSTobias Grosser  *
933d169d70bSTobias Grosser  * Given the declaration of a static or member method, returns its kind.
934d169d70bSTobias Grosser  */
get_kind(const isl_class & clazz,FunctionDecl * method)935*3f9bf9f4Spatacca static Method::Kind get_kind(const isl_class &clazz, FunctionDecl *method)
936d169d70bSTobias Grosser {
937*3f9bf9f4Spatacca 	if (generator::is_constructor(method))
938*3f9bf9f4Spatacca 		return Method::Kind::constructor;
939*3f9bf9f4Spatacca 	else if (generator::is_static(clazz, method))
940*3f9bf9f4Spatacca 		return Method::Kind::static_method;
941d169d70bSTobias Grosser 	else
942*3f9bf9f4Spatacca 		return Method::Kind::member_method;
943*3f9bf9f4Spatacca }
944*3f9bf9f4Spatacca 
945*3f9bf9f4Spatacca /* Return the callback argument of "fd", if there is any.
946*3f9bf9f4Spatacca  * Return NULL otherwise.
947*3f9bf9f4Spatacca  */
find_callback_arg(FunctionDecl * fd)948*3f9bf9f4Spatacca static ParmVarDecl *find_callback_arg(FunctionDecl *fd)
949*3f9bf9f4Spatacca {
950*3f9bf9f4Spatacca 	int num_params = fd->getNumParams();
951*3f9bf9f4Spatacca 
952*3f9bf9f4Spatacca 	for (int i = 0; i < num_params; ++i) {
953*3f9bf9f4Spatacca 		ParmVarDecl *param = fd->getParamDecl(i);
954*3f9bf9f4Spatacca 		if (generator::is_callback(param->getType()))
955*3f9bf9f4Spatacca 			return param;
956*3f9bf9f4Spatacca 	}
957*3f9bf9f4Spatacca 
958*3f9bf9f4Spatacca 	return NULL;
959*3f9bf9f4Spatacca }
960*3f9bf9f4Spatacca 
961*3f9bf9f4Spatacca /* Construct a C++ method object from the class to which is belongs,
962*3f9bf9f4Spatacca  * the isl function from which it is derived and the method name.
963*3f9bf9f4Spatacca  *
964*3f9bf9f4Spatacca  * Perform any renaming of the method that may be required and
965*3f9bf9f4Spatacca  * determine the type of the method.
966*3f9bf9f4Spatacca  */
Method(const isl_class & clazz,FunctionDecl * fd,const std::string & name)967*3f9bf9f4Spatacca Method::Method(const isl_class &clazz, FunctionDecl *fd,
968*3f9bf9f4Spatacca 	const std::string &name) :
969*3f9bf9f4Spatacca 		clazz(clazz), fd(fd), name(rename_method(name)),
970*3f9bf9f4Spatacca 		kind(get_kind(clazz, fd)),
971*3f9bf9f4Spatacca 		callback(find_callback_arg(fd))
972*3f9bf9f4Spatacca {
973*3f9bf9f4Spatacca }
974*3f9bf9f4Spatacca 
975*3f9bf9f4Spatacca /* Construct a C++ method object from the class to which is belongs and
976*3f9bf9f4Spatacca  * the isl function from which it is derived.
977*3f9bf9f4Spatacca  *
978*3f9bf9f4Spatacca  * Obtain the default method name and continue
979*3f9bf9f4Spatacca  * with the generic constructor.
980*3f9bf9f4Spatacca  */
Method(const isl_class & clazz,FunctionDecl * fd)981*3f9bf9f4Spatacca Method::Method(const isl_class &clazz, FunctionDecl *fd) :
982*3f9bf9f4Spatacca 	Method(clazz, fd, clazz.method_name(fd))
983*3f9bf9f4Spatacca {
984*3f9bf9f4Spatacca }
985*3f9bf9f4Spatacca 
986*3f9bf9f4Spatacca /* Return the number of parameters of the corresponding C function.
987*3f9bf9f4Spatacca  *
988*3f9bf9f4Spatacca  * If the method has a callback argument, we reduce the number of parameters
989*3f9bf9f4Spatacca  * that are exposed by one to hide the user pointer from the interface. On
990*3f9bf9f4Spatacca  * the C++ side no user pointer is needed, as arguments can be forwarded
991*3f9bf9f4Spatacca  * as part of the std::function argument which specifies the callback function.
992*3f9bf9f4Spatacca  *
993*3f9bf9f4Spatacca  * The user pointer is also removed from the number of parameters
994*3f9bf9f4Spatacca  * of the C function because the pair of callback and user pointer
995*3f9bf9f4Spatacca  * is considered as a single argument that is printed as a whole
996*3f9bf9f4Spatacca  * by Method::print_param_use.
997*3f9bf9f4Spatacca  */
c_num_params() const998*3f9bf9f4Spatacca int Method::c_num_params() const
999*3f9bf9f4Spatacca {
1000*3f9bf9f4Spatacca 	return fd->getNumParams() - (callback != NULL);
1001*3f9bf9f4Spatacca }
1002*3f9bf9f4Spatacca 
1003*3f9bf9f4Spatacca /* Return the number of parameters of the method
1004*3f9bf9f4Spatacca  * (including the implicit "this").
1005*3f9bf9f4Spatacca  *
1006*3f9bf9f4Spatacca  * By default, it is the same as the number of parameters
1007*3f9bf9f4Spatacca  * of the corresponding C function.
1008*3f9bf9f4Spatacca  */
num_params() const1009*3f9bf9f4Spatacca int Method::num_params() const
1010*3f9bf9f4Spatacca {
1011*3f9bf9f4Spatacca 	return c_num_params();
1012*3f9bf9f4Spatacca }
1013*3f9bf9f4Spatacca 
1014*3f9bf9f4Spatacca /* Print the arguments from "start" (inclusive) to "end" (exclusive)
1015*3f9bf9f4Spatacca  * as arguments to a method of C function call, using "print_arg"
1016*3f9bf9f4Spatacca  * to print each individual argument.
1017*3f9bf9f4Spatacca  */
print_arg_list(std::ostream & os,int start,int end,const std::function<void (int i)> & print_arg)1018*3f9bf9f4Spatacca void Method::print_arg_list(std::ostream &os, int start, int end,
1019*3f9bf9f4Spatacca 	const std::function<void(int i)> &print_arg)
1020*3f9bf9f4Spatacca {
1021*3f9bf9f4Spatacca 	os << "(";
1022*3f9bf9f4Spatacca 	for (int i = start; i < end; ++i) {
1023*3f9bf9f4Spatacca 		if (i != start)
1024*3f9bf9f4Spatacca 			os << ", ";
1025*3f9bf9f4Spatacca 		print_arg(i);
1026*3f9bf9f4Spatacca 	}
1027*3f9bf9f4Spatacca 	os << ")";
1028*3f9bf9f4Spatacca }
1029*3f9bf9f4Spatacca 
1030*3f9bf9f4Spatacca /* Print the arguments to the method call, using "print_arg"
1031*3f9bf9f4Spatacca  * to print each individual argument.
1032*3f9bf9f4Spatacca  */
print_cpp_arg_list(std::ostream & os,const std::function<void (int i)> & print_arg) const1033*3f9bf9f4Spatacca void Method::print_cpp_arg_list(std::ostream &os,
1034*3f9bf9f4Spatacca 	const std::function<void(int i)> &print_arg) const
1035*3f9bf9f4Spatacca {
1036*3f9bf9f4Spatacca 	int first_param = kind == member_method ? 1 : 0;
1037*3f9bf9f4Spatacca 	print_arg_list(os, first_param, num_params(), print_arg);
1038*3f9bf9f4Spatacca }
1039*3f9bf9f4Spatacca 
1040*3f9bf9f4Spatacca /* Should the parameter at position "pos" be a copy (rather than
1041*3f9bf9f4Spatacca  * a const reference)?
1042*3f9bf9f4Spatacca  *
1043*3f9bf9f4Spatacca  * Strictly speaking, a copy is only needed on isl types that are
1044*3f9bf9f4Spatacca  * not marked __isl_keep, since those will be release()'d
1045*3f9bf9f4Spatacca  * by code printed by Method::print_param_use.
1046*3f9bf9f4Spatacca  *
1047*3f9bf9f4Spatacca  * However, there may be other arguments such as integer types
1048*3f9bf9f4Spatacca  * that are more naturally passed as a copy.
1049*3f9bf9f4Spatacca  * The default is therefore to require a copy, except for
1050*3f9bf9f4Spatacca  * arguments marked __isl_keep, string arguments or callback arguments.
1051*3f9bf9f4Spatacca  */
param_needs_copy(int pos) const1052*3f9bf9f4Spatacca bool Method::param_needs_copy(int pos) const
1053*3f9bf9f4Spatacca {
1054*3f9bf9f4Spatacca 	ParmVarDecl *param = get_param(pos);
1055*3f9bf9f4Spatacca 	QualType type = param->getOriginalType();
1056*3f9bf9f4Spatacca 
1057*3f9bf9f4Spatacca 	if (generator::keeps(param))
1058*3f9bf9f4Spatacca 		return false;
1059*3f9bf9f4Spatacca 	if (generator::is_string(type) || generator::is_callback(type))
1060*3f9bf9f4Spatacca 		return false;
1061*3f9bf9f4Spatacca 	return true;
1062*3f9bf9f4Spatacca }
1063*3f9bf9f4Spatacca 
1064*3f9bf9f4Spatacca /* Return the method argument at position "pos".
1065*3f9bf9f4Spatacca  */
get_param(int pos) const1066*3f9bf9f4Spatacca clang::ParmVarDecl *Method::get_param(int pos) const
1067*3f9bf9f4Spatacca {
1068*3f9bf9f4Spatacca 	return fd->getParamDecl(pos);
1069*3f9bf9f4Spatacca }
1070*3f9bf9f4Spatacca 
1071*3f9bf9f4Spatacca /* Construct a method that performs one or more conversions
1072*3f9bf9f4Spatacca  * from the original Method (without conversions),
1073*3f9bf9f4Spatacca  * the name of the type to which "this" should be converted and
1074*3f9bf9f4Spatacca  * a function for determining the arguments of the constructed method.
1075*3f9bf9f4Spatacca  */
ConversionMethod(const Method & method,const std::string & this_type,const std::function<clang::ParmVarDecl * (int pos)> & get_param)1076*3f9bf9f4Spatacca ConversionMethod::ConversionMethod(const Method &method,
1077*3f9bf9f4Spatacca 	const std::string &this_type,
1078*3f9bf9f4Spatacca 	const std::function<clang::ParmVarDecl *(int pos)> &get_param) :
1079*3f9bf9f4Spatacca 		NoCopyMethod(method), this_type(this_type),
1080*3f9bf9f4Spatacca 		get_param_fn(get_param)
1081*3f9bf9f4Spatacca {
1082*3f9bf9f4Spatacca }
1083*3f9bf9f4Spatacca 
1084*3f9bf9f4Spatacca /* Construct a method that only performs a conversion on "this"
1085*3f9bf9f4Spatacca  * from the original Method (without conversions) and
1086*3f9bf9f4Spatacca  * the name of the type to which "this" should be converted.
1087*3f9bf9f4Spatacca  *
1088*3f9bf9f4Spatacca  * Call the generic constructor with
1089*3f9bf9f4Spatacca  * a function for determining the arguments of the constructed method
1090*3f9bf9f4Spatacca  * that performs no conversion.
1091*3f9bf9f4Spatacca  */
ConversionMethod(const Method & method,const std::string & this_type)1092*3f9bf9f4Spatacca ConversionMethod::ConversionMethod(const Method &method,
1093*3f9bf9f4Spatacca 	const std::string &this_type) :
1094*3f9bf9f4Spatacca 		ConversionMethod(method, this_type, [this] (int pos) {
1095*3f9bf9f4Spatacca 			return Method::get_param(pos);
1096*3f9bf9f4Spatacca 		})
1097*3f9bf9f4Spatacca {
1098*3f9bf9f4Spatacca }
1099*3f9bf9f4Spatacca 
1100*3f9bf9f4Spatacca /* Construct a method that performs one or more argument conversions
1101*3f9bf9f4Spatacca  * from the original Method (without conversions) and
1102*3f9bf9f4Spatacca  * a function for determining the arguments of the constructed method.
1103*3f9bf9f4Spatacca  *
1104*3f9bf9f4Spatacca  * Call the generic constructor with method.clazz.name as "this" type,
1105*3f9bf9f4Spatacca  * indicating that "this" should not be converted.
1106*3f9bf9f4Spatacca  */
ConversionMethod(const Method & method,const std::function<clang::ParmVarDecl * (int pos)> & get_param)1107*3f9bf9f4Spatacca ConversionMethod::ConversionMethod(const Method &method,
1108*3f9bf9f4Spatacca 	const std::function<clang::ParmVarDecl *(int pos)> &get_param) :
1109*3f9bf9f4Spatacca 		ConversionMethod(method, method.clazz.name, get_param)
1110*3f9bf9f4Spatacca {
1111*3f9bf9f4Spatacca }
1112*3f9bf9f4Spatacca 
1113*3f9bf9f4Spatacca /* Should the parameter at position "pos" be a copy (rather than
1114*3f9bf9f4Spatacca  * a const reference)?
1115*3f9bf9f4Spatacca  *
1116*3f9bf9f4Spatacca  * Parameters of isl type do not need to be a copy.
1117*3f9bf9f4Spatacca  * For other types, use the same defaults as Method.
1118*3f9bf9f4Spatacca  */
param_needs_copy(int pos) const1119*3f9bf9f4Spatacca bool NoCopyMethod::param_needs_copy(int pos) const
1120*3f9bf9f4Spatacca {
1121*3f9bf9f4Spatacca 	ParmVarDecl *param = get_param(pos);
1122*3f9bf9f4Spatacca 	QualType type = param->getOriginalType();
1123*3f9bf9f4Spatacca 
1124*3f9bf9f4Spatacca 	if (generator::is_isl_type(type))
1125*3f9bf9f4Spatacca 		return false;
1126*3f9bf9f4Spatacca 
1127*3f9bf9f4Spatacca 	return Method::param_needs_copy(pos);
1128*3f9bf9f4Spatacca }
1129*3f9bf9f4Spatacca 
1130*3f9bf9f4Spatacca /* Return the method argument at position "pos".
1131*3f9bf9f4Spatacca  *
1132*3f9bf9f4Spatacca  * Call get_param_fn to determine this argument.
1133*3f9bf9f4Spatacca  */
get_param(int pos) const1134*3f9bf9f4Spatacca clang::ParmVarDecl *ConversionMethod::get_param(int pos) const
1135*3f9bf9f4Spatacca {
1136*3f9bf9f4Spatacca 	return get_param_fn(pos);
1137*3f9bf9f4Spatacca }
1138*3f9bf9f4Spatacca 
1139*3f9bf9f4Spatacca /* Print a call to the method (without the arguments),
1140*3f9bf9f4Spatacca  * with "ns" the namespace of the generated C++ bindings.
1141*3f9bf9f4Spatacca  *
1142*3f9bf9f4Spatacca  * If "this_type" is different from the name of the class of the method,
1143*3f9bf9f4Spatacca  * then "this" needs to be converted to that type before
1144*3f9bf9f4Spatacca  * the call is performed.
1145*3f9bf9f4Spatacca  */
print_call(std::ostream & os,const std::string & ns) const1146*3f9bf9f4Spatacca void ConversionMethod::print_call(std::ostream &os, const std::string &ns) const
1147*3f9bf9f4Spatacca {
1148*3f9bf9f4Spatacca 	if (clazz.name == this_type) {
1149*3f9bf9f4Spatacca 		os << "this->";
1150*3f9bf9f4Spatacca 	} else {
1151*3f9bf9f4Spatacca 		auto cpp_type = ns + cpp_generator::type2cpp(this_type);
1152*3f9bf9f4Spatacca 		os << cpp_type << "(*this).";
1153*3f9bf9f4Spatacca 	}
1154*3f9bf9f4Spatacca 	os << name;
1155*3f9bf9f4Spatacca }
1156*3f9bf9f4Spatacca 
1157*3f9bf9f4Spatacca /* Construct an object representing a C++ method for setting an enum
1158*3f9bf9f4Spatacca  * from the class to which is belongs,
1159*3f9bf9f4Spatacca  * the isl function from which it is derived and the method and enum names.
1160*3f9bf9f4Spatacca  */
EnumMethod(const isl_class & clazz,FunctionDecl * fd,const std::string & method_name,const std::string & enum_name)1161*3f9bf9f4Spatacca EnumMethod::EnumMethod(const isl_class &clazz, FunctionDecl *fd,
1162*3f9bf9f4Spatacca 	const std::string &method_name, const std::string &enum_name) :
1163*3f9bf9f4Spatacca 		Method(clazz, fd, method_name), enum_name(enum_name)
1164*3f9bf9f4Spatacca {
1165*3f9bf9f4Spatacca }
1166*3f9bf9f4Spatacca 
1167*3f9bf9f4Spatacca /* Print the use of the argument at position "pos" to "os".
1168*3f9bf9f4Spatacca  *
1169*3f9bf9f4Spatacca  * If the position is beyond the number of method arguments,
1170*3f9bf9f4Spatacca  * then it corresponds to the enum value corresponding to this EnumMethod.
1171*3f9bf9f4Spatacca  * Otherwise, delegate to Method::print_param_use.
1172*3f9bf9f4Spatacca  */
print_param_use(ostream & os,int pos) const1173*3f9bf9f4Spatacca void EnumMethod::print_param_use(ostream &os, int pos) const
1174*3f9bf9f4Spatacca {
1175*3f9bf9f4Spatacca 	if (pos == num_params())
1176*3f9bf9f4Spatacca 		os << enum_name;
1177*3f9bf9f4Spatacca 	else
1178*3f9bf9f4Spatacca 		Method::print_param_use(os, pos);
1179*3f9bf9f4Spatacca }
1180*3f9bf9f4Spatacca 
1181*3f9bf9f4Spatacca /* Return the number of parameters of the method
1182*3f9bf9f4Spatacca  * (including the implicit "this").
1183*3f9bf9f4Spatacca  *
1184*3f9bf9f4Spatacca  * The last argument of the C function does not appear in the method call,
1185*3f9bf9f4Spatacca  * because it is replaced by a break-up into several methods.
1186*3f9bf9f4Spatacca  */
num_params() const1187*3f9bf9f4Spatacca int EnumMethod::num_params() const
1188*3f9bf9f4Spatacca {
1189*3f9bf9f4Spatacca 	return Method::num_params() - 1;
1190*3f9bf9f4Spatacca }
1191*3f9bf9f4Spatacca 
1192*3f9bf9f4Spatacca /* Initialize a class method printer from the stream onto which the methods
1193*3f9bf9f4Spatacca  * are printed, the class method description and the C++ interface generator.
1194*3f9bf9f4Spatacca  */
class_printer(std::ostream & os,const isl_class & clazz,cpp_generator & generator,bool declarations)1195*3f9bf9f4Spatacca cpp_generator::class_printer::class_printer(std::ostream &os,
1196*3f9bf9f4Spatacca 		const isl_class &clazz, cpp_generator &generator,
1197*3f9bf9f4Spatacca 		bool declarations) :
1198*3f9bf9f4Spatacca 	os(os), clazz(clazz), cppstring(type2cpp(clazz)), generator(generator),
1199*3f9bf9f4Spatacca 	declarations(declarations)
1200*3f9bf9f4Spatacca {
1201d169d70bSTobias Grosser }
1202