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