1*d169d70bSTobias Grosser /*
2*d169d70bSTobias Grosser  * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
3*d169d70bSTobias Grosser  *
4*d169d70bSTobias Grosser  * Redistribution and use in source and binary forms, with or without
5*d169d70bSTobias Grosser  * modification, are permitted provided that the following conditions
6*d169d70bSTobias Grosser  * are met:
7*d169d70bSTobias Grosser  *
8*d169d70bSTobias Grosser  *    1. Redistributions of source code must retain the above copyright
9*d169d70bSTobias Grosser  *       notice, this list of conditions and the following disclaimer.
10*d169d70bSTobias Grosser  *
11*d169d70bSTobias Grosser  *    2. Redistributions in binary form must reproduce the above
12*d169d70bSTobias Grosser  *       copyright notice, this list of conditions and the following
13*d169d70bSTobias Grosser  *       disclaimer in the documentation and/or other materials provided
14*d169d70bSTobias Grosser  *       with the distribution.
15*d169d70bSTobias Grosser  *
16*d169d70bSTobias Grosser  * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY
17*d169d70bSTobias Grosser  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*d169d70bSTobias Grosser  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19*d169d70bSTobias Grosser  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR
20*d169d70bSTobias Grosser  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21*d169d70bSTobias Grosser  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22*d169d70bSTobias Grosser  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23*d169d70bSTobias Grosser  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24*d169d70bSTobias Grosser  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25*d169d70bSTobias Grosser  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26*d169d70bSTobias Grosser  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*d169d70bSTobias Grosser  *
28*d169d70bSTobias Grosser  * The views and conclusions contained in the software and documentation
29*d169d70bSTobias Grosser  * are those of the authors and should not be interpreted as
30*d169d70bSTobias Grosser  * representing official policies, either expressed or implied, of
31*d169d70bSTobias Grosser  * Tobias Grosser.
32*d169d70bSTobias Grosser  */
33*d169d70bSTobias Grosser 
34*d169d70bSTobias Grosser #include <cstdarg>
35*d169d70bSTobias Grosser #include <cstdio>
36*d169d70bSTobias Grosser #include <iostream>
37*d169d70bSTobias Grosser #include <map>
38*d169d70bSTobias Grosser #include <sstream>
39*d169d70bSTobias Grosser #include <string>
40*d169d70bSTobias Grosser #include <vector>
41*d169d70bSTobias Grosser 
42*d169d70bSTobias Grosser #include "cpp.h"
43*d169d70bSTobias Grosser #include "isl_config.h"
44*d169d70bSTobias Grosser 
45*d169d70bSTobias Grosser /* Print string formatted according to "fmt" to ostream "os".
46*d169d70bSTobias Grosser  *
47*d169d70bSTobias Grosser  * This osprintf method allows us to use printf style formatting constructs when
48*d169d70bSTobias Grosser  * writing to an ostream.
49*d169d70bSTobias Grosser  */
50*d169d70bSTobias Grosser static void osprintf(ostream &os, const char *format, ...)
51*d169d70bSTobias Grosser {
52*d169d70bSTobias Grosser 	va_list arguments;
53*d169d70bSTobias Grosser 	char *string_pointer;
54*d169d70bSTobias Grosser 	size_t size;
55*d169d70bSTobias Grosser 
56*d169d70bSTobias Grosser 	va_start(arguments, format);
57*d169d70bSTobias Grosser 	size = vsnprintf(NULL, 0, format, arguments);
58*d169d70bSTobias Grosser 	string_pointer = new char[size + 1];
59*d169d70bSTobias Grosser 	va_end(arguments);
60*d169d70bSTobias Grosser 	va_start(arguments, format);
61*d169d70bSTobias Grosser 	vsnprintf(string_pointer, size + 1, format, arguments);
62*d169d70bSTobias Grosser 	va_end(arguments);
63*d169d70bSTobias Grosser 	os << string_pointer;
64*d169d70bSTobias Grosser 	delete[] string_pointer;
65*d169d70bSTobias Grosser }
66*d169d70bSTobias Grosser 
67*d169d70bSTobias Grosser /* Convert "l" to a string.
68*d169d70bSTobias Grosser  */
69*d169d70bSTobias Grosser static std::string to_string(long l)
70*d169d70bSTobias Grosser {
71*d169d70bSTobias Grosser 	std::ostringstream strm;
72*d169d70bSTobias Grosser 	strm << l;
73*d169d70bSTobias Grosser 	return strm.str();
74*d169d70bSTobias Grosser }
75*d169d70bSTobias Grosser 
76*d169d70bSTobias Grosser /* Generate a cpp interface based on the extracted types and functions.
77*d169d70bSTobias Grosser  *
78*d169d70bSTobias Grosser  * Print first a set of forward declarations for all isl wrapper
79*d169d70bSTobias Grosser  * classes, then the declarations of the classes, and at the end all
80*d169d70bSTobias Grosser  * implementations.
81*d169d70bSTobias Grosser  *
82*d169d70bSTobias Grosser  * If checked C++ bindings are being generated,
83*d169d70bSTobias Grosser  * then wrap them in a namespace to avoid conflicts
84*d169d70bSTobias Grosser  * with the default C++ bindings (with automatic checks using exceptions).
85*d169d70bSTobias Grosser  */
86*d169d70bSTobias Grosser void cpp_generator::generate()
87*d169d70bSTobias Grosser {
88*d169d70bSTobias Grosser 	ostream &os = cout;
89*d169d70bSTobias Grosser 
90*d169d70bSTobias Grosser 	osprintf(os, "\n");
91*d169d70bSTobias Grosser 	osprintf(os, "namespace isl {\n\n");
92*d169d70bSTobias Grosser 	if (checked)
93*d169d70bSTobias Grosser 		osprintf(os, "namespace checked {\n\n");
94*d169d70bSTobias Grosser 
95*d169d70bSTobias Grosser 	print_forward_declarations(os);
96*d169d70bSTobias Grosser 	osprintf(os, "\n");
97*d169d70bSTobias Grosser 	print_declarations(os);
98*d169d70bSTobias Grosser 	osprintf(os, "\n");
99*d169d70bSTobias Grosser 	print_implementations(os);
100*d169d70bSTobias Grosser 
101*d169d70bSTobias Grosser 	if (checked)
102*d169d70bSTobias Grosser 		osprintf(os, "} // namespace checked\n");
103*d169d70bSTobias Grosser 	osprintf(os, "} // namespace isl\n");
104*d169d70bSTobias Grosser }
105*d169d70bSTobias Grosser 
106*d169d70bSTobias Grosser /* Print forward declarations for all classes to "os".
107*d169d70bSTobias Grosser */
108*d169d70bSTobias Grosser void cpp_generator::print_forward_declarations(ostream &os)
109*d169d70bSTobias Grosser {
110*d169d70bSTobias Grosser 	map<string, isl_class>::iterator ci;
111*d169d70bSTobias Grosser 
112*d169d70bSTobias Grosser 	osprintf(os, "// forward declarations\n");
113*d169d70bSTobias Grosser 
114*d169d70bSTobias Grosser 	for (ci = classes.begin(); ci != classes.end(); ++ci)
115*d169d70bSTobias Grosser 		print_class_forward_decl(os, ci->second);
116*d169d70bSTobias Grosser }
117*d169d70bSTobias Grosser 
118*d169d70bSTobias Grosser /* Print all declarations to "os".
119*d169d70bSTobias Grosser  */
120*d169d70bSTobias Grosser void cpp_generator::print_declarations(ostream &os)
121*d169d70bSTobias Grosser {
122*d169d70bSTobias Grosser 	map<string, isl_class>::iterator ci;
123*d169d70bSTobias Grosser 	bool first = true;
124*d169d70bSTobias Grosser 
125*d169d70bSTobias Grosser 	for (ci = classes.begin(); ci != classes.end(); ++ci) {
126*d169d70bSTobias Grosser 		if (first)
127*d169d70bSTobias Grosser 			first = false;
128*d169d70bSTobias Grosser 		else
129*d169d70bSTobias Grosser 			osprintf(os, "\n");
130*d169d70bSTobias Grosser 
131*d169d70bSTobias Grosser 		print_class(os, ci->second);
132*d169d70bSTobias Grosser 	}
133*d169d70bSTobias Grosser }
134*d169d70bSTobias Grosser 
135*d169d70bSTobias Grosser /* Print all implementations to "os".
136*d169d70bSTobias Grosser  */
137*d169d70bSTobias Grosser void cpp_generator::print_implementations(ostream &os)
138*d169d70bSTobias Grosser {
139*d169d70bSTobias Grosser 	map<string, isl_class>::iterator ci;
140*d169d70bSTobias Grosser 	bool first = true;
141*d169d70bSTobias Grosser 
142*d169d70bSTobias Grosser 	for (ci = classes.begin(); ci != classes.end(); ++ci) {
143*d169d70bSTobias Grosser 		if (first)
144*d169d70bSTobias Grosser 			first = false;
145*d169d70bSTobias Grosser 		else
146*d169d70bSTobias Grosser 			osprintf(os, "\n");
147*d169d70bSTobias Grosser 
148*d169d70bSTobias Grosser 		print_class_impl(os, ci->second);
149*d169d70bSTobias Grosser 	}
150*d169d70bSTobias Grosser }
151*d169d70bSTobias Grosser 
152*d169d70bSTobias Grosser /* Print declarations for class "clazz" to "os".
153*d169d70bSTobias Grosser  */
154*d169d70bSTobias Grosser void cpp_generator::print_class(ostream &os, const isl_class &clazz)
155*d169d70bSTobias Grosser {
156*d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
157*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
158*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
159*d169d70bSTobias Grosser 
160*d169d70bSTobias Grosser 	osprintf(os, "// declarations for isl::%s\n", cppname);
161*d169d70bSTobias Grosser 
162*d169d70bSTobias Grosser 	print_class_factory_decl(os, clazz);
163*d169d70bSTobias Grosser 	osprintf(os, "\n");
164*d169d70bSTobias Grosser 	osprintf(os, "class %s {\n", cppname);
165*d169d70bSTobias Grosser 	print_class_factory_decl(os, clazz, "  friend ");
166*d169d70bSTobias Grosser 	osprintf(os, "\n");
167*d169d70bSTobias Grosser 	osprintf(os, "  %s *ptr = nullptr;\n", name);
168*d169d70bSTobias Grosser 	osprintf(os, "\n");
169*d169d70bSTobias Grosser 	print_private_constructors_decl(os, clazz);
170*d169d70bSTobias Grosser 	osprintf(os, "\n");
171*d169d70bSTobias Grosser 	osprintf(os, "public:\n");
172*d169d70bSTobias Grosser 	print_public_constructors_decl(os, clazz);
173*d169d70bSTobias Grosser 	print_constructors_decl(os, clazz);
174*d169d70bSTobias Grosser 	print_copy_assignment_decl(os, clazz);
175*d169d70bSTobias Grosser 	print_destructor_decl(os, clazz);
176*d169d70bSTobias Grosser 	print_ptr_decl(os, clazz);
177*d169d70bSTobias Grosser 	print_get_ctx_decl(os);
178*d169d70bSTobias Grosser 	osprintf(os, "\n");
179*d169d70bSTobias Grosser 	print_methods_decl(os, clazz);
180*d169d70bSTobias Grosser 
181*d169d70bSTobias Grosser 	osprintf(os, "};\n");
182*d169d70bSTobias Grosser }
183*d169d70bSTobias Grosser 
184*d169d70bSTobias Grosser /* Print forward declaration of class "clazz" to "os".
185*d169d70bSTobias Grosser  */
186*d169d70bSTobias Grosser void cpp_generator::print_class_forward_decl(ostream &os,
187*d169d70bSTobias Grosser 	const isl_class &clazz)
188*d169d70bSTobias Grosser {
189*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
190*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
191*d169d70bSTobias Grosser 
192*d169d70bSTobias Grosser 	osprintf(os, "class %s;\n", cppname);
193*d169d70bSTobias Grosser }
194*d169d70bSTobias Grosser 
195*d169d70bSTobias Grosser /* Print global factory functions to "os".
196*d169d70bSTobias Grosser  *
197*d169d70bSTobias Grosser  * Each class has two global factory functions:
198*d169d70bSTobias Grosser  *
199*d169d70bSTobias Grosser  * 	set manage(__isl_take isl_set *ptr);
200*d169d70bSTobias Grosser  * 	set manage_copy(__isl_keep isl_set *ptr);
201*d169d70bSTobias Grosser  *
202*d169d70bSTobias Grosser  * A user can construct isl C++ objects from a raw pointer and indicate whether
203*d169d70bSTobias Grosser  * they intend to take the ownership of the object or not through these global
204*d169d70bSTobias Grosser  * factory functions. This ensures isl object creation is very explicit and
205*d169d70bSTobias Grosser  * pointers are not converted by accident. Thanks to overloading, manage() and
206*d169d70bSTobias Grosser  * manage_copy() can be called on any isl raw pointer and the corresponding
207*d169d70bSTobias Grosser  * object is automatically created, without the user having to choose the right
208*d169d70bSTobias Grosser  * isl object type.
209*d169d70bSTobias Grosser  */
210*d169d70bSTobias Grosser void cpp_generator::print_class_factory_decl(ostream &os,
211*d169d70bSTobias Grosser 	const isl_class &clazz, const std::string &prefix)
212*d169d70bSTobias Grosser {
213*d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
214*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
215*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
216*d169d70bSTobias Grosser 
217*d169d70bSTobias Grosser 	os << prefix;
218*d169d70bSTobias Grosser 	osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name);
219*d169d70bSTobias Grosser 	os << prefix;
220*d169d70bSTobias Grosser 	osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n",
221*d169d70bSTobias Grosser 		cppname, name);
222*d169d70bSTobias Grosser }
223*d169d70bSTobias Grosser 
224*d169d70bSTobias Grosser /* Print declarations of private constructors for class "clazz" to "os".
225*d169d70bSTobias Grosser  *
226*d169d70bSTobias Grosser  * Each class has currently one private constructor:
227*d169d70bSTobias Grosser  *
228*d169d70bSTobias Grosser  * 	1) Constructor from a plain isl_* C pointer
229*d169d70bSTobias Grosser  *
230*d169d70bSTobias Grosser  * Example:
231*d169d70bSTobias Grosser  *
232*d169d70bSTobias Grosser  * 	set(__isl_take isl_set *ptr);
233*d169d70bSTobias Grosser  *
234*d169d70bSTobias Grosser  * The raw pointer constructor is kept private. Object creation is only
235*d169d70bSTobias Grosser  * possible through manage() or manage_copy().
236*d169d70bSTobias Grosser  */
237*d169d70bSTobias Grosser void cpp_generator::print_private_constructors_decl(ostream &os,
238*d169d70bSTobias Grosser 	const isl_class &clazz)
239*d169d70bSTobias Grosser {
240*d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
241*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
242*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
243*d169d70bSTobias Grosser 
244*d169d70bSTobias Grosser 	osprintf(os, "  inline explicit %s(__isl_take %s *ptr);\n", cppname,
245*d169d70bSTobias Grosser 		 name);
246*d169d70bSTobias Grosser }
247*d169d70bSTobias Grosser 
248*d169d70bSTobias Grosser /* Print declarations of public constructors for class "clazz" to "os".
249*d169d70bSTobias Grosser  *
250*d169d70bSTobias Grosser  * Each class currently has two public constructors:
251*d169d70bSTobias Grosser  *
252*d169d70bSTobias Grosser  * 	1) A default constructor
253*d169d70bSTobias Grosser  * 	2) A copy constructor
254*d169d70bSTobias Grosser  *
255*d169d70bSTobias Grosser  * Example:
256*d169d70bSTobias Grosser  *
257*d169d70bSTobias Grosser  *	set();
258*d169d70bSTobias Grosser  *	set(const set &set);
259*d169d70bSTobias Grosser  */
260*d169d70bSTobias Grosser void cpp_generator::print_public_constructors_decl(ostream &os,
261*d169d70bSTobias Grosser 	const isl_class &clazz)
262*d169d70bSTobias Grosser {
263*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
264*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
265*d169d70bSTobias Grosser 	osprintf(os, "  inline /* implicit */ %s();\n", cppname);
266*d169d70bSTobias Grosser 
267*d169d70bSTobias Grosser 	osprintf(os, "  inline /* implicit */ %s(const %s &obj);\n",
268*d169d70bSTobias Grosser 		 cppname, cppname);
269*d169d70bSTobias Grosser }
270*d169d70bSTobias Grosser 
271*d169d70bSTobias Grosser /* Print declarations for constructors for class "class" to "os".
272*d169d70bSTobias Grosser  *
273*d169d70bSTobias Grosser  * For each isl function that is marked as __isl_constructor,
274*d169d70bSTobias Grosser  * add a corresponding C++ constructor.
275*d169d70bSTobias Grosser  *
276*d169d70bSTobias Grosser  * Example:
277*d169d70bSTobias Grosser  *
278*d169d70bSTobias Grosser  * 	inline /\* implicit *\/ union_set(basic_set bset);
279*d169d70bSTobias Grosser  * 	inline /\* implicit *\/ union_set(set set);
280*d169d70bSTobias Grosser  * 	inline explicit val(ctx ctx, long i);
281*d169d70bSTobias Grosser  * 	inline explicit val(ctx ctx, const std::string &str);
282*d169d70bSTobias Grosser  */
283*d169d70bSTobias Grosser void cpp_generator::print_constructors_decl(ostream &os,
284*d169d70bSTobias Grosser        const isl_class &clazz)
285*d169d70bSTobias Grosser {
286*d169d70bSTobias Grosser 	set<FunctionDecl *>::const_iterator in;
287*d169d70bSTobias Grosser 	const set<FunctionDecl *> &constructors = clazz.constructors;
288*d169d70bSTobias Grosser 
289*d169d70bSTobias Grosser 	for (in = constructors.begin(); in != constructors.end(); ++in) {
290*d169d70bSTobias Grosser 		FunctionDecl *cons = *in;
291*d169d70bSTobias Grosser 		string fullname = cons->getName();
292*d169d70bSTobias Grosser 		function_kind kind = function_kind_constructor;
293*d169d70bSTobias Grosser 
294*d169d70bSTobias Grosser 		print_method_decl(os, clazz, fullname, cons, kind);
295*d169d70bSTobias Grosser 	}
296*d169d70bSTobias Grosser }
297*d169d70bSTobias Grosser 
298*d169d70bSTobias Grosser /* Print declarations of copy assignment operator for class "clazz"
299*d169d70bSTobias Grosser  * to "os".
300*d169d70bSTobias Grosser  *
301*d169d70bSTobias Grosser  * Each class has one assignment operator.
302*d169d70bSTobias Grosser  *
303*d169d70bSTobias Grosser  * 	isl:set &set::operator=(set obj)
304*d169d70bSTobias Grosser  *
305*d169d70bSTobias Grosser  */
306*d169d70bSTobias Grosser void cpp_generator::print_copy_assignment_decl(ostream &os,
307*d169d70bSTobias Grosser 	const isl_class &clazz)
308*d169d70bSTobias Grosser {
309*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
310*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
311*d169d70bSTobias Grosser 
312*d169d70bSTobias Grosser 	osprintf(os, "  inline %s &operator=(%s obj);\n", cppname, cppname);
313*d169d70bSTobias Grosser }
314*d169d70bSTobias Grosser 
315*d169d70bSTobias Grosser /* Print declaration of destructor for class "clazz" to "os".
316*d169d70bSTobias Grosser  */
317*d169d70bSTobias Grosser void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz)
318*d169d70bSTobias Grosser {
319*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
320*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
321*d169d70bSTobias Grosser 
322*d169d70bSTobias Grosser 	osprintf(os, "  inline ~%s();\n", cppname);
323*d169d70bSTobias Grosser }
324*d169d70bSTobias Grosser 
325*d169d70bSTobias Grosser /* Print declaration of pointer functions for class "clazz" to "os".
326*d169d70bSTobias Grosser  *
327*d169d70bSTobias Grosser  * To obtain a raw pointer three functions are provided:
328*d169d70bSTobias Grosser  *
329*d169d70bSTobias Grosser  * 	1) __isl_give isl_set *copy()
330*d169d70bSTobias Grosser  *
331*d169d70bSTobias Grosser  * 	  Returns a pointer to a _copy_ of the internal object
332*d169d70bSTobias Grosser  *
333*d169d70bSTobias Grosser  * 	2) __isl_keep isl_set *get()
334*d169d70bSTobias Grosser  *
335*d169d70bSTobias Grosser  * 	  Returns a pointer to the internal object
336*d169d70bSTobias Grosser  *
337*d169d70bSTobias Grosser  * 	3) __isl_give isl_set *release()
338*d169d70bSTobias Grosser  *
339*d169d70bSTobias Grosser  * 	  Returns a pointer to the internal object and resets the
340*d169d70bSTobias Grosser  * 	  internal pointer to nullptr.
341*d169d70bSTobias Grosser  *
342*d169d70bSTobias Grosser  * We also provide functionality to explicitly check if a pointer is
343*d169d70bSTobias Grosser  * currently managed by this object.
344*d169d70bSTobias Grosser  *
345*d169d70bSTobias Grosser  * 	4) bool is_null()
346*d169d70bSTobias Grosser  *
347*d169d70bSTobias Grosser  * 	  Check if the current object is a null pointer.
348*d169d70bSTobias Grosser  *
349*d169d70bSTobias Grosser  * The functions get() and release() model the value_ptr proposed in
350*d169d70bSTobias Grosser  * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
351*d169d70bSTobias Grosser  * The copy() function is an extension to allow the user to explicitly
352*d169d70bSTobias Grosser  * copy the underlying object.
353*d169d70bSTobias Grosser  *
354*d169d70bSTobias Grosser  * Also generate a declaration to delete copy() for r-values, for
355*d169d70bSTobias Grosser  * r-values release() should be used to avoid unnecessary copies.
356*d169d70bSTobias Grosser  */
357*d169d70bSTobias Grosser void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz)
358*d169d70bSTobias Grosser {
359*d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
360*d169d70bSTobias Grosser 
361*d169d70bSTobias Grosser 	osprintf(os, "  inline __isl_give %s *copy() const &;\n", name);
362*d169d70bSTobias Grosser 	osprintf(os, "  inline __isl_give %s *copy() && = delete;\n", name);
363*d169d70bSTobias Grosser 	osprintf(os, "  inline __isl_keep %s *get() const;\n", name);
364*d169d70bSTobias Grosser 	osprintf(os, "  inline __isl_give %s *release();\n", name);
365*d169d70bSTobias Grosser 	osprintf(os, "  inline bool is_null() const;\n");
366*d169d70bSTobias Grosser }
367*d169d70bSTobias Grosser 
368*d169d70bSTobias Grosser /* Print the declaration of the get_ctx method.
369*d169d70bSTobias Grosser  */
370*d169d70bSTobias Grosser void cpp_generator::print_get_ctx_decl(ostream &os)
371*d169d70bSTobias Grosser {
372*d169d70bSTobias Grosser 	osprintf(os, "  inline ctx get_ctx() const;\n");
373*d169d70bSTobias Grosser }
374*d169d70bSTobias Grosser 
375*d169d70bSTobias Grosser /* Print declarations for methods in class "clazz" to "os".
376*d169d70bSTobias Grosser  */
377*d169d70bSTobias Grosser void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz)
378*d169d70bSTobias Grosser {
379*d169d70bSTobias Grosser 	map<string, set<FunctionDecl *> >::const_iterator it;
380*d169d70bSTobias Grosser 
381*d169d70bSTobias Grosser 	for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
382*d169d70bSTobias Grosser 		print_method_group_decl(os, clazz, it->first, it->second);
383*d169d70bSTobias Grosser }
384*d169d70bSTobias Grosser 
385*d169d70bSTobias Grosser /* Print declarations for methods "methods" of name "fullname" in class "clazz"
386*d169d70bSTobias Grosser  * to "os".
387*d169d70bSTobias Grosser  *
388*d169d70bSTobias Grosser  * "fullname" is the name of the generated C++ method.  It commonly corresponds
389*d169d70bSTobias Grosser  * to the isl name, with the object type prefix dropped.
390*d169d70bSTobias Grosser  * In case of overloaded methods, the result type suffix has also been removed.
391*d169d70bSTobias Grosser  */
392*d169d70bSTobias Grosser void cpp_generator::print_method_group_decl(ostream &os, const isl_class &clazz,
393*d169d70bSTobias Grosser 	const string &fullname, const set<FunctionDecl *> &methods)
394*d169d70bSTobias Grosser {
395*d169d70bSTobias Grosser 	set<FunctionDecl *>::const_iterator it;
396*d169d70bSTobias Grosser 
397*d169d70bSTobias Grosser 	for (it = methods.begin(); it != methods.end(); ++it) {
398*d169d70bSTobias Grosser 		function_kind kind = get_method_kind(clazz, *it);
399*d169d70bSTobias Grosser 		print_method_decl(os, clazz, fullname, *it, kind);
400*d169d70bSTobias Grosser 	}
401*d169d70bSTobias Grosser }
402*d169d70bSTobias Grosser 
403*d169d70bSTobias Grosser /* Print declarations for "method" in class "clazz" to "os".
404*d169d70bSTobias Grosser  *
405*d169d70bSTobias Grosser  * "fullname" is the name of the generated C++ method.  It commonly corresponds
406*d169d70bSTobias Grosser  * to the isl name, with the object type prefix dropped.
407*d169d70bSTobias Grosser  * In case of overloaded methods, the result type suffix has also been removed.
408*d169d70bSTobias Grosser  *
409*d169d70bSTobias Grosser  * "kind" specifies the kind of method that should be generated.
410*d169d70bSTobias Grosser  */
411*d169d70bSTobias Grosser void cpp_generator::print_method_decl(ostream &os, const isl_class &clazz,
412*d169d70bSTobias Grosser 	const string &fullname, FunctionDecl *method, function_kind kind)
413*d169d70bSTobias Grosser {
414*d169d70bSTobias Grosser 	print_method_header(os, clazz, method, fullname, true, kind);
415*d169d70bSTobias Grosser }
416*d169d70bSTobias Grosser 
417*d169d70bSTobias Grosser /* Print implementations for class "clazz" to "os".
418*d169d70bSTobias Grosser  */
419*d169d70bSTobias Grosser void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
420*d169d70bSTobias Grosser {
421*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
422*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
423*d169d70bSTobias Grosser 
424*d169d70bSTobias Grosser 	osprintf(os, "// implementations for isl::%s\n", cppname);
425*d169d70bSTobias Grosser 
426*d169d70bSTobias Grosser 	print_class_factory_impl(os, clazz);
427*d169d70bSTobias Grosser 	osprintf(os, "\n");
428*d169d70bSTobias Grosser 	print_public_constructors_impl(os, clazz);
429*d169d70bSTobias Grosser 	osprintf(os, "\n");
430*d169d70bSTobias Grosser 	print_private_constructors_impl(os, clazz);
431*d169d70bSTobias Grosser 	osprintf(os, "\n");
432*d169d70bSTobias Grosser 	print_constructors_impl(os, clazz);
433*d169d70bSTobias Grosser 	osprintf(os, "\n");
434*d169d70bSTobias Grosser 	print_copy_assignment_impl(os, clazz);
435*d169d70bSTobias Grosser 	osprintf(os, "\n");
436*d169d70bSTobias Grosser 	print_destructor_impl(os, clazz);
437*d169d70bSTobias Grosser 	osprintf(os, "\n");
438*d169d70bSTobias Grosser 	print_ptr_impl(os, clazz);
439*d169d70bSTobias Grosser 	osprintf(os, "\n");
440*d169d70bSTobias Grosser 	print_get_ctx_impl(os, clazz);
441*d169d70bSTobias Grosser 	osprintf(os, "\n");
442*d169d70bSTobias Grosser 	print_methods_impl(os, clazz);
443*d169d70bSTobias Grosser }
444*d169d70bSTobias Grosser 
445*d169d70bSTobias Grosser /* Print code for throwing an exception corresponding to the last error
446*d169d70bSTobias Grosser  * that occurred on "ctx".
447*d169d70bSTobias Grosser  * This assumes that a valid isl::ctx is available in the "ctx" variable,
448*d169d70bSTobias Grosser  * e.g., through a prior call to print_save_ctx.
449*d169d70bSTobias Grosser  */
450*d169d70bSTobias Grosser static void print_throw_last_error(ostream &os)
451*d169d70bSTobias Grosser {
452*d169d70bSTobias Grosser 	osprintf(os, "    exception::throw_last_error(ctx);\n");
453*d169d70bSTobias Grosser }
454*d169d70bSTobias Grosser 
455*d169d70bSTobias Grosser /* Print code for throwing an exception on NULL input.
456*d169d70bSTobias Grosser  */
457*d169d70bSTobias Grosser static void print_throw_NULL_input(ostream &os)
458*d169d70bSTobias Grosser {
459*d169d70bSTobias Grosser 	osprintf(os, "    exception::throw_NULL_input(__FILE__, __LINE__);\n");
460*d169d70bSTobias Grosser }
461*d169d70bSTobias Grosser 
462*d169d70bSTobias Grosser /* Print implementation of global factory functions to "os".
463*d169d70bSTobias Grosser  *
464*d169d70bSTobias Grosser  * Each class has two global factory functions:
465*d169d70bSTobias Grosser  *
466*d169d70bSTobias Grosser  * 	set manage(__isl_take isl_set *ptr);
467*d169d70bSTobias Grosser  * 	set manage_copy(__isl_keep isl_set *ptr);
468*d169d70bSTobias Grosser  *
469*d169d70bSTobias Grosser  * Unless checked C++ bindings are being generated,
470*d169d70bSTobias Grosser  * both functions require the argument to be non-NULL.
471*d169d70bSTobias Grosser  * An exception is thrown if anything went wrong during the copying
472*d169d70bSTobias Grosser  * in manage_copy.
473*d169d70bSTobias Grosser  * During the copying, isl is made not to print any error message
474*d169d70bSTobias Grosser  * because the error message is included in the exception.
475*d169d70bSTobias Grosser  */
476*d169d70bSTobias Grosser void cpp_generator::print_class_factory_impl(ostream &os,
477*d169d70bSTobias Grosser 	const isl_class &clazz)
478*d169d70bSTobias Grosser {
479*d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
480*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
481*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
482*d169d70bSTobias Grosser 
483*d169d70bSTobias Grosser 	osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
484*d169d70bSTobias Grosser 	if (!checked) {
485*d169d70bSTobias Grosser 		osprintf(os, "  if (!ptr)\n");
486*d169d70bSTobias Grosser 		print_throw_NULL_input(os);
487*d169d70bSTobias Grosser 	}
488*d169d70bSTobias Grosser 	osprintf(os, "  return %s(ptr);\n", cppname);
489*d169d70bSTobias Grosser 	osprintf(os, "}\n");
490*d169d70bSTobias Grosser 
491*d169d70bSTobias Grosser 	osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
492*d169d70bSTobias Grosser 		name);
493*d169d70bSTobias Grosser 	if (!checked) {
494*d169d70bSTobias Grosser 		osprintf(os, "  if (!ptr)\n");
495*d169d70bSTobias Grosser 		print_throw_NULL_input(os);
496*d169d70bSTobias Grosser 		osprintf(os, "  auto ctx = %s_get_ctx(ptr);\n", name);
497*d169d70bSTobias Grosser 		print_on_error_continue(os);
498*d169d70bSTobias Grosser 	}
499*d169d70bSTobias Grosser 	osprintf(os, "  ptr = %s_copy(ptr);\n", name);
500*d169d70bSTobias Grosser 	if (!checked) {
501*d169d70bSTobias Grosser 		osprintf(os, "  if (!ptr)\n");
502*d169d70bSTobias Grosser 		print_throw_last_error(os);
503*d169d70bSTobias Grosser 	}
504*d169d70bSTobias Grosser 	osprintf(os, "  return %s(ptr);\n", cppname);
505*d169d70bSTobias Grosser 	osprintf(os, "}\n");
506*d169d70bSTobias Grosser }
507*d169d70bSTobias Grosser 
508*d169d70bSTobias Grosser /* Print implementations of private constructors for class "clazz" to "os".
509*d169d70bSTobias Grosser  */
510*d169d70bSTobias Grosser void cpp_generator::print_private_constructors_impl(ostream &os,
511*d169d70bSTobias Grosser 	const isl_class &clazz)
512*d169d70bSTobias Grosser {
513*d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
514*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
515*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
516*d169d70bSTobias Grosser 
517*d169d70bSTobias Grosser 	osprintf(os, "%s::%s(__isl_take %s *ptr)\n    : ptr(ptr) {}\n",
518*d169d70bSTobias Grosser 		 cppname, cppname, name);
519*d169d70bSTobias Grosser }
520*d169d70bSTobias Grosser 
521*d169d70bSTobias Grosser /* Print implementations of public constructors for class "clazz" to "os".
522*d169d70bSTobias Grosser  *
523*d169d70bSTobias Grosser  * Throw an exception from the copy constructor if anything went wrong
524*d169d70bSTobias Grosser  * during the copying or if the input is NULL.
525*d169d70bSTobias Grosser  * During the copying, isl is made not to print any error message
526*d169d70bSTobias Grosser  * because the error message is included in the exception.
527*d169d70bSTobias Grosser  * No exceptions are thrown if checked C++ bindings
528*d169d70bSTobias Grosser  * are being generated,
529*d169d70bSTobias Grosser  */
530*d169d70bSTobias Grosser void cpp_generator::print_public_constructors_impl(ostream &os,
531*d169d70bSTobias Grosser 	const isl_class &clazz)
532*d169d70bSTobias Grosser {
533*d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
534*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
535*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
536*d169d70bSTobias Grosser 
537*d169d70bSTobias Grosser 	osprintf(os, "%s::%s()\n    : ptr(nullptr) {}\n\n", cppname, cppname);
538*d169d70bSTobias Grosser 	osprintf(os, "%s::%s(const %s &obj)\n    : ptr(nullptr)\n",
539*d169d70bSTobias Grosser 		 cppname, cppname, cppname);
540*d169d70bSTobias Grosser 	osprintf(os, "{\n");
541*d169d70bSTobias Grosser 	if (!checked) {
542*d169d70bSTobias Grosser 		osprintf(os, "  if (!obj.ptr)\n");
543*d169d70bSTobias Grosser 		print_throw_NULL_input(os);
544*d169d70bSTobias Grosser 		osprintf(os, "  auto ctx = %s_get_ctx(obj.ptr);\n", name);
545*d169d70bSTobias Grosser 		print_on_error_continue(os);
546*d169d70bSTobias Grosser 	}
547*d169d70bSTobias Grosser 	osprintf(os, "  ptr = obj.copy();\n");
548*d169d70bSTobias Grosser 	if (!checked) {
549*d169d70bSTobias Grosser 		osprintf(os, "  if (obj.ptr && !ptr)\n");
550*d169d70bSTobias Grosser 		print_throw_last_error(os);
551*d169d70bSTobias Grosser 	}
552*d169d70bSTobias Grosser 	osprintf(os, "}\n");
553*d169d70bSTobias Grosser }
554*d169d70bSTobias Grosser 
555*d169d70bSTobias Grosser /* Print implementations of constructors for class "clazz" to "os".
556*d169d70bSTobias Grosser  */
557*d169d70bSTobias Grosser void cpp_generator::print_constructors_impl(ostream &os,
558*d169d70bSTobias Grosser        const isl_class &clazz)
559*d169d70bSTobias Grosser {
560*d169d70bSTobias Grosser 	set<FunctionDecl *>::const_iterator in;
561*d169d70bSTobias Grosser 	const set<FunctionDecl *> constructors = clazz.constructors;
562*d169d70bSTobias Grosser 
563*d169d70bSTobias Grosser 	for (in = constructors.begin(); in != constructors.end(); ++in) {
564*d169d70bSTobias Grosser 		FunctionDecl *cons = *in;
565*d169d70bSTobias Grosser 		string fullname = cons->getName();
566*d169d70bSTobias Grosser 		function_kind kind = function_kind_constructor;
567*d169d70bSTobias Grosser 
568*d169d70bSTobias Grosser 		print_method_impl(os, clazz, fullname, cons, kind);
569*d169d70bSTobias Grosser 	}
570*d169d70bSTobias Grosser }
571*d169d70bSTobias Grosser 
572*d169d70bSTobias Grosser /* Print implementation of copy assignment operator for class "clazz" to "os".
573*d169d70bSTobias Grosser  */
574*d169d70bSTobias Grosser void cpp_generator::print_copy_assignment_impl(ostream &os,
575*d169d70bSTobias Grosser 	const isl_class &clazz)
576*d169d70bSTobias Grosser {
577*d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
578*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
579*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
580*d169d70bSTobias Grosser 
581*d169d70bSTobias Grosser 	osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname,
582*d169d70bSTobias Grosser 		 cppname, cppname);
583*d169d70bSTobias Grosser 	osprintf(os, "  std::swap(this->ptr, obj.ptr);\n", name);
584*d169d70bSTobias Grosser 	osprintf(os, "  return *this;\n");
585*d169d70bSTobias Grosser 	osprintf(os, "}\n");
586*d169d70bSTobias Grosser }
587*d169d70bSTobias Grosser 
588*d169d70bSTobias Grosser /* Print implementation of destructor for class "clazz" to "os".
589*d169d70bSTobias Grosser  */
590*d169d70bSTobias Grosser void cpp_generator::print_destructor_impl(ostream &os,
591*d169d70bSTobias Grosser 	const isl_class &clazz)
592*d169d70bSTobias Grosser {
593*d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
594*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
595*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
596*d169d70bSTobias Grosser 
597*d169d70bSTobias Grosser 	osprintf(os, "%s::~%s() {\n", cppname, cppname);
598*d169d70bSTobias Grosser 	osprintf(os, "  if (ptr)\n");
599*d169d70bSTobias Grosser 	osprintf(os, "    %s_free(ptr);\n", name);
600*d169d70bSTobias Grosser 	osprintf(os, "}\n");
601*d169d70bSTobias Grosser }
602*d169d70bSTobias Grosser 
603*d169d70bSTobias Grosser /* Print implementation of ptr() functions for class "clazz" to "os".
604*d169d70bSTobias Grosser  */
605*d169d70bSTobias Grosser void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
606*d169d70bSTobias Grosser {
607*d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
608*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
609*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
610*d169d70bSTobias Grosser 
611*d169d70bSTobias Grosser 	osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
612*d169d70bSTobias Grosser 	osprintf(os, "  return %s_copy(ptr);\n", name);
613*d169d70bSTobias Grosser 	osprintf(os, "}\n\n");
614*d169d70bSTobias Grosser 	osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
615*d169d70bSTobias Grosser 	osprintf(os, "  return ptr;\n");
616*d169d70bSTobias Grosser 	osprintf(os, "}\n\n");
617*d169d70bSTobias Grosser 	osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
618*d169d70bSTobias Grosser 	osprintf(os, "  %s *tmp = ptr;\n", name);
619*d169d70bSTobias Grosser 	osprintf(os, "  ptr = nullptr;\n");
620*d169d70bSTobias Grosser 	osprintf(os, "  return tmp;\n");
621*d169d70bSTobias Grosser 	osprintf(os, "}\n\n");
622*d169d70bSTobias Grosser 	osprintf(os, "bool %s::is_null() const {\n", cppname);
623*d169d70bSTobias Grosser 	osprintf(os, "  return ptr == nullptr;\n");
624*d169d70bSTobias Grosser 	osprintf(os, "}\n");
625*d169d70bSTobias Grosser }
626*d169d70bSTobias Grosser 
627*d169d70bSTobias Grosser /* Print the implementation of the get_ctx method.
628*d169d70bSTobias Grosser  */
629*d169d70bSTobias Grosser void cpp_generator::print_get_ctx_impl(ostream &os, const isl_class &clazz)
630*d169d70bSTobias Grosser {
631*d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
632*d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
633*d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
634*d169d70bSTobias Grosser 
635*d169d70bSTobias Grosser 	osprintf(os, "ctx %s::get_ctx() const {\n", cppname);
636*d169d70bSTobias Grosser 	osprintf(os, "  return ctx(%s_get_ctx(ptr));\n", name);
637*d169d70bSTobias Grosser 	osprintf(os, "}\n");
638*d169d70bSTobias Grosser }
639*d169d70bSTobias Grosser 
640*d169d70bSTobias Grosser /* Print definitions for methods of class "clazz" to "os".
641*d169d70bSTobias Grosser  */
642*d169d70bSTobias Grosser void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz)
643*d169d70bSTobias Grosser {
644*d169d70bSTobias Grosser 	map<string, set<FunctionDecl *> >::const_iterator it;
645*d169d70bSTobias Grosser 	bool first = true;
646*d169d70bSTobias Grosser 
647*d169d70bSTobias Grosser 	for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) {
648*d169d70bSTobias Grosser 		if (first)
649*d169d70bSTobias Grosser 			first = false;
650*d169d70bSTobias Grosser 		else
651*d169d70bSTobias Grosser 			osprintf(os, "\n");
652*d169d70bSTobias Grosser 		print_method_group_impl(os, clazz, it->first, it->second);
653*d169d70bSTobias Grosser 	}
654*d169d70bSTobias Grosser }
655*d169d70bSTobias Grosser 
656*d169d70bSTobias Grosser /* Print definitions for methods "methods" of name "fullname" in class "clazz"
657*d169d70bSTobias Grosser  * to "os".
658*d169d70bSTobias Grosser  *
659*d169d70bSTobias Grosser  * "fullname" is the name of the generated C++ method.  It commonly corresponds
660*d169d70bSTobias Grosser  * to the isl name, with the object type prefix dropped.
661*d169d70bSTobias Grosser  * In case of overloaded methods, the result type suffix has also been removed.
662*d169d70bSTobias Grosser  *
663*d169d70bSTobias Grosser  * "kind" specifies the kind of method that should be generated.
664*d169d70bSTobias Grosser  */
665*d169d70bSTobias Grosser void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz,
666*d169d70bSTobias Grosser 	const string &fullname, const set<FunctionDecl *> &methods)
667*d169d70bSTobias Grosser {
668*d169d70bSTobias Grosser 	set<FunctionDecl *>::const_iterator it;
669*d169d70bSTobias Grosser 	bool first = true;
670*d169d70bSTobias Grosser 
671*d169d70bSTobias Grosser 	for (it = methods.begin(); it != methods.end(); ++it) {
672*d169d70bSTobias Grosser 		function_kind kind;
673*d169d70bSTobias Grosser 		if (first)
674*d169d70bSTobias Grosser 			first = false;
675*d169d70bSTobias Grosser 		else
676*d169d70bSTobias Grosser 			osprintf(os, "\n");
677*d169d70bSTobias Grosser 		kind = get_method_kind(clazz, *it);
678*d169d70bSTobias Grosser 		print_method_impl(os, clazz, fullname, *it, kind);
679*d169d70bSTobias Grosser 	}
680*d169d70bSTobias Grosser }
681*d169d70bSTobias Grosser 
682*d169d70bSTobias Grosser /* Print the use of "param" to "os".
683*d169d70bSTobias Grosser  *
684*d169d70bSTobias Grosser  * "load_from_this_ptr" specifies whether the parameter should be loaded from
685*d169d70bSTobias Grosser  * the this-ptr.  In case a value is loaded from a this pointer, the original
686*d169d70bSTobias Grosser  * value must be preserved and must consequently be copied.  Values that are
687*d169d70bSTobias Grosser  * loaded from parameters do not need to be preserved, as such values will
688*d169d70bSTobias Grosser  * already be copies of the actual parameters.  It is consequently possible
689*d169d70bSTobias Grosser  * to directly take the pointer from these values, which saves
690*d169d70bSTobias Grosser  * an unnecessary copy.
691*d169d70bSTobias Grosser  *
692*d169d70bSTobias Grosser  * In case the parameter is a callback function, two parameters get printed,
693*d169d70bSTobias Grosser  * a wrapper for the callback function and a pointer to the actual
694*d169d70bSTobias Grosser  * callback function.  The wrapper is expected to be available
695*d169d70bSTobias Grosser  * in a previously declared variable <name>_lambda, while
696*d169d70bSTobias Grosser  * the actual callback function is expected to be stored
697*d169d70bSTobias Grosser  * in a structure called <name>_data.
698*d169d70bSTobias Grosser  * The caller of this function must ensure that these variables exist.
699*d169d70bSTobias Grosser  */
700*d169d70bSTobias Grosser void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param,
701*d169d70bSTobias Grosser 	bool load_from_this_ptr)
702*d169d70bSTobias Grosser {
703*d169d70bSTobias Grosser 	string name = param->getName().str();
704*d169d70bSTobias Grosser 	const char *name_str = name.c_str();
705*d169d70bSTobias Grosser 	QualType type = param->getOriginalType();
706*d169d70bSTobias Grosser 
707*d169d70bSTobias Grosser 	if (type->isIntegerType()) {
708*d169d70bSTobias Grosser 		osprintf(os, "%s", name_str);
709*d169d70bSTobias Grosser 		return;
710*d169d70bSTobias Grosser 	}
711*d169d70bSTobias Grosser 
712*d169d70bSTobias Grosser 	if (is_string(type)) {
713*d169d70bSTobias Grosser 		osprintf(os, "%s.c_str()", name_str);
714*d169d70bSTobias Grosser 		return;
715*d169d70bSTobias Grosser 	}
716*d169d70bSTobias Grosser 
717*d169d70bSTobias Grosser 	if (is_callback(type)) {
718*d169d70bSTobias Grosser 		osprintf(os, "%s_lambda, ", name_str);
719*d169d70bSTobias Grosser 		osprintf(os, "&%s_data", name_str);
720*d169d70bSTobias Grosser 		return;
721*d169d70bSTobias Grosser 	}
722*d169d70bSTobias Grosser 
723*d169d70bSTobias Grosser 	if (!load_from_this_ptr && !is_callback(type))
724*d169d70bSTobias Grosser 		osprintf(os, "%s.", name_str);
725*d169d70bSTobias Grosser 
726*d169d70bSTobias Grosser 	if (keeps(param)) {
727*d169d70bSTobias Grosser 		osprintf(os, "get()");
728*d169d70bSTobias Grosser 	} else {
729*d169d70bSTobias Grosser 		if (load_from_this_ptr)
730*d169d70bSTobias Grosser 			osprintf(os, "copy()");
731*d169d70bSTobias Grosser 		else
732*d169d70bSTobias Grosser 			osprintf(os, "release()");
733*d169d70bSTobias Grosser 	}
734*d169d70bSTobias Grosser }
735*d169d70bSTobias Grosser 
736*d169d70bSTobias Grosser /* Print code that checks that all isl object arguments to "method" are valid
737*d169d70bSTobias Grosser  * (not NULL) and throws an exception if they are not.
738*d169d70bSTobias Grosser  * "kind" specifies the kind of method that is being generated.
739*d169d70bSTobias Grosser  *
740*d169d70bSTobias Grosser  * If checked bindings are being generated,
741*d169d70bSTobias Grosser  * then no such check is performed.
742*d169d70bSTobias Grosser  */
743*d169d70bSTobias Grosser void cpp_generator::print_argument_validity_check(ostream &os,
744*d169d70bSTobias Grosser 	FunctionDecl *method, function_kind kind)
745*d169d70bSTobias Grosser {
746*d169d70bSTobias Grosser 	int n;
747*d169d70bSTobias Grosser 	bool first = true;
748*d169d70bSTobias Grosser 
749*d169d70bSTobias Grosser 	if (checked)
750*d169d70bSTobias Grosser 		return;
751*d169d70bSTobias Grosser 
752*d169d70bSTobias Grosser 	n = method->getNumParams();
753*d169d70bSTobias Grosser 	for (int i = 0; i < n; ++i) {
754*d169d70bSTobias Grosser 		bool is_this;
755*d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
756*d169d70bSTobias Grosser 		string name = param->getName().str();
757*d169d70bSTobias Grosser 		const char *name_str = name.c_str();
758*d169d70bSTobias Grosser 		QualType type = param->getOriginalType();
759*d169d70bSTobias Grosser 
760*d169d70bSTobias Grosser 		is_this = i == 0 && kind == function_kind_member_method;
761*d169d70bSTobias Grosser 		if (!is_this && (is_isl_ctx(type) || !is_isl_type(type)))
762*d169d70bSTobias Grosser 			continue;
763*d169d70bSTobias Grosser 
764*d169d70bSTobias Grosser 		if (first)
765*d169d70bSTobias Grosser 			osprintf(os, "  if (");
766*d169d70bSTobias Grosser 		else
767*d169d70bSTobias Grosser 			osprintf(os, " || ");
768*d169d70bSTobias Grosser 
769*d169d70bSTobias Grosser 		if (is_this)
770*d169d70bSTobias Grosser 			osprintf(os, "!ptr");
771*d169d70bSTobias Grosser 		else
772*d169d70bSTobias Grosser 			osprintf(os, "%s.is_null()", name_str);
773*d169d70bSTobias Grosser 
774*d169d70bSTobias Grosser 		first = false;
775*d169d70bSTobias Grosser 	}
776*d169d70bSTobias Grosser 	if (first)
777*d169d70bSTobias Grosser 		return;
778*d169d70bSTobias Grosser 	osprintf(os, ")\n");
779*d169d70bSTobias Grosser 	print_throw_NULL_input(os);
780*d169d70bSTobias Grosser }
781*d169d70bSTobias Grosser 
782*d169d70bSTobias Grosser /* Print code for saving a copy of the isl::ctx available at the start
783*d169d70bSTobias Grosser  * of the method "method" in a "ctx" variable, for use in exception handling.
784*d169d70bSTobias Grosser  * "kind" specifies what kind of method "method" is.
785*d169d70bSTobias Grosser  *
786*d169d70bSTobias Grosser  * If checked bindings are being generated,
787*d169d70bSTobias Grosser  * then the "ctx" variable is not needed.
788*d169d70bSTobias Grosser  * If "method" is a member function, then obtain the isl_ctx from
789*d169d70bSTobias Grosser  * the "this" object.
790*d169d70bSTobias Grosser  * If the first argument of the method is an isl::ctx, then use that one,
791*d169d70bSTobias Grosser  * assuming it is not already called "ctx".
792*d169d70bSTobias Grosser  * Otherwise, save a copy of the isl::ctx associated to the first argument
793*d169d70bSTobias Grosser  * of isl object type.
794*d169d70bSTobias Grosser  */
795*d169d70bSTobias Grosser void cpp_generator::print_save_ctx(ostream &os, FunctionDecl *method,
796*d169d70bSTobias Grosser 	function_kind kind)
797*d169d70bSTobias Grosser {
798*d169d70bSTobias Grosser 	int n;
799*d169d70bSTobias Grosser 	ParmVarDecl *param = method->getParamDecl(0);
800*d169d70bSTobias Grosser 	QualType type = param->getOriginalType();
801*d169d70bSTobias Grosser 
802*d169d70bSTobias Grosser 	if (checked)
803*d169d70bSTobias Grosser 		return;
804*d169d70bSTobias Grosser 	if (kind == function_kind_member_method) {
805*d169d70bSTobias Grosser 		osprintf(os, "  auto ctx = get_ctx();\n");
806*d169d70bSTobias Grosser 		return;
807*d169d70bSTobias Grosser 	}
808*d169d70bSTobias Grosser 	if (is_isl_ctx(type)) {
809*d169d70bSTobias Grosser 		const char *name;
810*d169d70bSTobias Grosser 
811*d169d70bSTobias Grosser 		name = param->getName().str().c_str();
812*d169d70bSTobias Grosser 		if (strcmp(name, "ctx") != 0)
813*d169d70bSTobias Grosser 			osprintf(os, "  auto ctx = %s;\n", name);
814*d169d70bSTobias Grosser 		return;
815*d169d70bSTobias Grosser 	}
816*d169d70bSTobias Grosser 	n = method->getNumParams();
817*d169d70bSTobias Grosser 	for (int i = 0; i < n; ++i) {
818*d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
819*d169d70bSTobias Grosser 		QualType type = param->getOriginalType();
820*d169d70bSTobias Grosser 
821*d169d70bSTobias Grosser 		if (!is_isl_type(type))
822*d169d70bSTobias Grosser 			continue;
823*d169d70bSTobias Grosser 		osprintf(os, "  auto ctx = %s.get_ctx();\n",
824*d169d70bSTobias Grosser 			param->getName().str().c_str());
825*d169d70bSTobias Grosser 		return;
826*d169d70bSTobias Grosser 	}
827*d169d70bSTobias Grosser }
828*d169d70bSTobias Grosser 
829*d169d70bSTobias Grosser /* Print code to make isl not print an error message when an error occurs
830*d169d70bSTobias Grosser  * within the current scope (if exceptions are available),
831*d169d70bSTobias Grosser  * since the error message will be included in the exception.
832*d169d70bSTobias Grosser  * If exceptions are not available, then exception::on_error
833*d169d70bSTobias Grosser  * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead.
834*d169d70bSTobias Grosser  *
835*d169d70bSTobias Grosser  * If checked bindings are being generated,
836*d169d70bSTobias Grosser  * then leave it to the user to decide what isl should do on error.
837*d169d70bSTobias Grosser  * Otherwise, assume that a valid isl::ctx is available in the "ctx" variable,
838*d169d70bSTobias Grosser  * e.g., through a prior call to print_save_ctx.
839*d169d70bSTobias Grosser  */
840*d169d70bSTobias Grosser void cpp_generator::print_on_error_continue(ostream &os)
841*d169d70bSTobias Grosser {
842*d169d70bSTobias Grosser 	if (checked)
843*d169d70bSTobias Grosser 		return;
844*d169d70bSTobias Grosser 	osprintf(os, "  options_scoped_set_on_error saved_on_error(ctx, "
845*d169d70bSTobias Grosser 		     "exception::on_error);\n");
846*d169d70bSTobias Grosser }
847*d169d70bSTobias Grosser 
848*d169d70bSTobias Grosser /* Print code that checks whether the execution of the core of "method"
849*d169d70bSTobias Grosser  * was successful.
850*d169d70bSTobias Grosser  *
851*d169d70bSTobias Grosser  * If checked bindings are being generated,
852*d169d70bSTobias Grosser  * then no checks are performed.
853*d169d70bSTobias Grosser  *
854*d169d70bSTobias Grosser  * Otherwise, first check if any of the callbacks failed with
855*d169d70bSTobias Grosser  * an exception.  If so, the "eptr" in the corresponding data structure
856*d169d70bSTobias Grosser  * contains the exception that was caught and that needs to be rethrown.
857*d169d70bSTobias Grosser  * Then check if the function call failed in any other way and throw
858*d169d70bSTobias Grosser  * the appropriate exception.
859*d169d70bSTobias Grosser  * In particular, if the return type is isl_stat or isl_bool,
860*d169d70bSTobias Grosser  * then a negative value indicates a failure.  If the return type
861*d169d70bSTobias Grosser  * is an isl type, then a NULL value indicates a failure.
862*d169d70bSTobias Grosser  * Assume print_save_ctx has made sure that a valid isl::ctx
863*d169d70bSTobias Grosser  * is available in the "ctx" variable.
864*d169d70bSTobias Grosser  */
865*d169d70bSTobias Grosser void cpp_generator::print_exceptional_execution_check(ostream &os,
866*d169d70bSTobias Grosser 	FunctionDecl *method)
867*d169d70bSTobias Grosser {
868*d169d70bSTobias Grosser 	int n;
869*d169d70bSTobias Grosser 	bool check_null, check_neg;
870*d169d70bSTobias Grosser 	QualType return_type = method->getReturnType();
871*d169d70bSTobias Grosser 
872*d169d70bSTobias Grosser 	if (checked)
873*d169d70bSTobias Grosser 		return;
874*d169d70bSTobias Grosser 
875*d169d70bSTobias Grosser 	n = method->getNumParams();
876*d169d70bSTobias Grosser 	for (int i = 0; i < n; ++i) {
877*d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
878*d169d70bSTobias Grosser 		const char *name;
879*d169d70bSTobias Grosser 
880*d169d70bSTobias Grosser 		if (!is_callback(param->getOriginalType()))
881*d169d70bSTobias Grosser 			continue;
882*d169d70bSTobias Grosser 		name = param->getName().str().c_str();
883*d169d70bSTobias Grosser 		osprintf(os, "  if (%s_data.eptr)\n", name);
884*d169d70bSTobias Grosser 		osprintf(os, "    std::rethrow_exception(%s_data.eptr);\n",
885*d169d70bSTobias Grosser 			name);
886*d169d70bSTobias Grosser 	}
887*d169d70bSTobias Grosser 
888*d169d70bSTobias Grosser 	check_neg = is_isl_stat(return_type) || is_isl_bool(return_type);
889*d169d70bSTobias Grosser 	check_null = is_isl_type(return_type);
890*d169d70bSTobias Grosser 	if (!check_null && !check_neg)
891*d169d70bSTobias Grosser 		return;
892*d169d70bSTobias Grosser 
893*d169d70bSTobias Grosser 	if (check_neg)
894*d169d70bSTobias Grosser 		osprintf(os, "  if (res < 0)\n");
895*d169d70bSTobias Grosser 	else
896*d169d70bSTobias Grosser 		osprintf(os, "  if (!res)\n");
897*d169d70bSTobias Grosser 	print_throw_last_error(os);
898*d169d70bSTobias Grosser }
899*d169d70bSTobias Grosser 
900*d169d70bSTobias Grosser /* Print definition for "method" in class "clazz" to "os".
901*d169d70bSTobias Grosser  *
902*d169d70bSTobias Grosser  * "fullname" is the name of the generated C++ method.  It commonly corresponds
903*d169d70bSTobias Grosser  * to the isl name, with the object type prefix dropped.
904*d169d70bSTobias Grosser  * In case of overloaded methods, the result type suffix has also been removed.
905*d169d70bSTobias Grosser  *
906*d169d70bSTobias Grosser  * "kind" specifies the kind of method that should be generated.
907*d169d70bSTobias Grosser  *
908*d169d70bSTobias Grosser  * This method distinguishes three kinds of methods: member methods, static
909*d169d70bSTobias Grosser  * methods, and constructors.
910*d169d70bSTobias Grosser  *
911*d169d70bSTobias Grosser  * Member methods call "method" by passing to the underlying isl function the
912*d169d70bSTobias Grosser  * isl object belonging to "this" as first argument and the remaining arguments
913*d169d70bSTobias Grosser  * as subsequent arguments. The result of the isl function is returned as a new
914*d169d70bSTobias Grosser  * object if the underlying isl function returns an isl_* ptr, as a bool
915*d169d70bSTobias Grosser  * if the isl function returns an isl_bool, as void if the isl functions
916*d169d70bSTobias Grosser  * returns an isl_stat,
917*d169d70bSTobias Grosser  * as std::string if the isl function returns 'const char *', and as
918*d169d70bSTobias Grosser  * unmodified return value otherwise.
919*d169d70bSTobias Grosser  * If checked C++ bindings are being generated,
920*d169d70bSTobias Grosser  * then an isl_bool return type is transformed into a boolean and
921*d169d70bSTobias Grosser  * an isl_stat into a stat since no exceptions can be generated
922*d169d70bSTobias Grosser  * on negative results from the isl function.
923*d169d70bSTobias Grosser  *
924*d169d70bSTobias Grosser  * Static methods call "method" by passing all arguments to the underlying isl
925*d169d70bSTobias Grosser  * function, as no this-pointer is available. The result is a newly managed
926*d169d70bSTobias Grosser  * isl C++ object.
927*d169d70bSTobias Grosser  *
928*d169d70bSTobias Grosser  * Constructors create a new object from a given set of input parameters. They
929*d169d70bSTobias Grosser  * do not return a value, but instead update the pointer stored inside the
930*d169d70bSTobias Grosser  * newly created object.
931*d169d70bSTobias Grosser  *
932*d169d70bSTobias Grosser  * If the method has a callback argument, we reduce the number of parameters
933*d169d70bSTobias Grosser  * that are exposed by one to hide the user pointer from the interface. On
934*d169d70bSTobias Grosser  * the C++ side no user pointer is needed, as arguments can be forwarded
935*d169d70bSTobias Grosser  * as part of the std::function argument which specifies the callback function.
936*d169d70bSTobias Grosser  *
937*d169d70bSTobias Grosser  * Unless checked C++ bindings are being generated,
938*d169d70bSTobias Grosser  * the inputs of the method are first checked for being valid isl objects and
939*d169d70bSTobias Grosser  * a copy of the associated isl::ctx is saved (if needed).
940*d169d70bSTobias Grosser  * If any failure occurs, either during the check for the inputs or
941*d169d70bSTobias Grosser  * during the isl function call, an exception is thrown.
942*d169d70bSTobias Grosser  * During the function call, isl is made not to print any error message
943*d169d70bSTobias Grosser  * because the error message is included in the exception.
944*d169d70bSTobias Grosser  */
945*d169d70bSTobias Grosser void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz,
946*d169d70bSTobias Grosser 	const string &fullname, FunctionDecl *method, function_kind kind)
947*d169d70bSTobias Grosser {
948*d169d70bSTobias Grosser 	string methodname = method->getName();
949*d169d70bSTobias Grosser 	int num_params = method->getNumParams();
950*d169d70bSTobias Grosser 	QualType return_type = method->getReturnType();
951*d169d70bSTobias Grosser 	string rettype_str = type2cpp(return_type);
952*d169d70bSTobias Grosser 	bool has_callback = false;
953*d169d70bSTobias Grosser 
954*d169d70bSTobias Grosser 	print_method_header(os, clazz, method, fullname, false, kind);
955*d169d70bSTobias Grosser 	osprintf(os, "{\n");
956*d169d70bSTobias Grosser 	print_argument_validity_check(os, method, kind);
957*d169d70bSTobias Grosser 	print_save_ctx(os, method, kind);
958*d169d70bSTobias Grosser 	print_on_error_continue(os);
959*d169d70bSTobias Grosser 
960*d169d70bSTobias Grosser 	for (int i = 0; i < num_params; ++i) {
961*d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
962*d169d70bSTobias Grosser 		if (is_callback(param->getType())) {
963*d169d70bSTobias Grosser 			has_callback = true;
964*d169d70bSTobias Grosser 			num_params -= 1;
965*d169d70bSTobias Grosser 			print_callback_local(os, param);
966*d169d70bSTobias Grosser 		}
967*d169d70bSTobias Grosser 	}
968*d169d70bSTobias Grosser 
969*d169d70bSTobias Grosser 	osprintf(os, "  auto res = %s(", methodname.c_str());
970*d169d70bSTobias Grosser 
971*d169d70bSTobias Grosser 	for (int i = 0; i < num_params; ++i) {
972*d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
973*d169d70bSTobias Grosser 		bool load_from_this_ptr = false;
974*d169d70bSTobias Grosser 
975*d169d70bSTobias Grosser 		if (i == 0 && kind == function_kind_member_method)
976*d169d70bSTobias Grosser 			load_from_this_ptr = true;
977*d169d70bSTobias Grosser 
978*d169d70bSTobias Grosser 		print_method_param_use(os, param, load_from_this_ptr);
979*d169d70bSTobias Grosser 
980*d169d70bSTobias Grosser 		if (i != num_params - 1)
981*d169d70bSTobias Grosser 			osprintf(os, ", ");
982*d169d70bSTobias Grosser 	}
983*d169d70bSTobias Grosser 	osprintf(os, ");\n");
984*d169d70bSTobias Grosser 
985*d169d70bSTobias Grosser 	print_exceptional_execution_check(os, method);
986*d169d70bSTobias Grosser 	if (kind == function_kind_constructor) {
987*d169d70bSTobias Grosser 		osprintf(os, "  ptr = res;\n");
988*d169d70bSTobias Grosser 	} else if (is_isl_type(return_type) ||
989*d169d70bSTobias Grosser 		    (checked &&
990*d169d70bSTobias Grosser 		     (is_isl_bool(return_type) || is_isl_stat(return_type)))) {
991*d169d70bSTobias Grosser 		osprintf(os, "  return manage(res);\n");
992*d169d70bSTobias Grosser 	} else if (has_callback) {
993*d169d70bSTobias Grosser 		osprintf(os, "  return %s(res);\n", rettype_str.c_str());
994*d169d70bSTobias Grosser 	} else if (is_string(return_type)) {
995*d169d70bSTobias Grosser 		osprintf(os, "  std::string tmp(res);\n");
996*d169d70bSTobias Grosser 		if (gives(method))
997*d169d70bSTobias Grosser 			osprintf(os, "  free(res);\n");
998*d169d70bSTobias Grosser 		osprintf(os, "  return tmp;\n");
999*d169d70bSTobias Grosser 	} else {
1000*d169d70bSTobias Grosser 		osprintf(os, "  return res;\n");
1001*d169d70bSTobias Grosser 	}
1002*d169d70bSTobias Grosser 
1003*d169d70bSTobias Grosser 	osprintf(os, "}\n");
1004*d169d70bSTobias Grosser }
1005*d169d70bSTobias Grosser 
1006*d169d70bSTobias Grosser /* Print the header for "method" in class "clazz" to "os".
1007*d169d70bSTobias Grosser  *
1008*d169d70bSTobias Grosser  * Print the header of a declaration if "is_declaration" is set, otherwise print
1009*d169d70bSTobias Grosser  * the header of a method definition.
1010*d169d70bSTobias Grosser  *
1011*d169d70bSTobias Grosser  * "fullname" is the name of the generated C++ method.  It commonly corresponds
1012*d169d70bSTobias Grosser  * to the isl name, with the object type prefix dropped.
1013*d169d70bSTobias Grosser  * In case of overloaded methods, the result type suffix has also been removed.
1014*d169d70bSTobias Grosser  *
1015*d169d70bSTobias Grosser  * "kind" specifies the kind of method that should be generated.
1016*d169d70bSTobias Grosser  *
1017*d169d70bSTobias Grosser  * This function prints headers for member methods, static methods, and
1018*d169d70bSTobias Grosser  * constructors, either for their declaration or definition.
1019*d169d70bSTobias Grosser  *
1020*d169d70bSTobias Grosser  * Member functions are declared as "const", as they do not change the current
1021*d169d70bSTobias Grosser  * object, but instead create a new object. They always retrieve the first
1022*d169d70bSTobias Grosser  * parameter of the original isl function from the this-pointer of the object,
1023*d169d70bSTobias Grosser  * such that only starting at the second parameter the parameters of the
1024*d169d70bSTobias Grosser  * original function become part of the method's interface.
1025*d169d70bSTobias Grosser  *
1026*d169d70bSTobias Grosser  * A function
1027*d169d70bSTobias Grosser  *
1028*d169d70bSTobias Grosser  * 	__isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
1029*d169d70bSTobias Grosser  * 		__isl_take isl_set *s2);
1030*d169d70bSTobias Grosser  *
1031*d169d70bSTobias Grosser  * is translated into:
1032*d169d70bSTobias Grosser  *
1033*d169d70bSTobias Grosser  * 	inline set intersect(set set2) const;
1034*d169d70bSTobias Grosser  *
1035*d169d70bSTobias Grosser  * For static functions and constructors all parameters of the original isl
1036*d169d70bSTobias Grosser  * function are exposed.
1037*d169d70bSTobias Grosser  *
1038*d169d70bSTobias Grosser  * Parameters that are defined as __isl_keep or are of type string, are passed
1039*d169d70bSTobias Grosser  * as const reference, which allows the compiler to optimize the parameter
1040*d169d70bSTobias Grosser  * transfer.
1041*d169d70bSTobias Grosser  *
1042*d169d70bSTobias Grosser  * Constructors are marked as explicit using the C++ keyword 'explicit' or as
1043*d169d70bSTobias Grosser  * implicit using a comment in place of the explicit keyword. By annotating
1044*d169d70bSTobias Grosser  * implicit constructors with a comment, users of the interface are made
1045*d169d70bSTobias Grosser  * aware of the potential danger that implicit construction is possible
1046*d169d70bSTobias Grosser  * for these constructors, whereas without a comment not every user would
1047*d169d70bSTobias Grosser  * know that implicit construction is allowed in absence of an explicit keyword.
1048*d169d70bSTobias Grosser  */
1049*d169d70bSTobias Grosser void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
1050*d169d70bSTobias Grosser 	FunctionDecl *method, const string &fullname, bool is_declaration,
1051*d169d70bSTobias Grosser 	function_kind kind)
1052*d169d70bSTobias Grosser {
1053*d169d70bSTobias Grosser 	string cname = fullname.substr(clazz.name.length() + 1);
1054*d169d70bSTobias Grosser 	string rettype_str = type2cpp(method->getReturnType());
1055*d169d70bSTobias Grosser 	string classname = type2cpp(clazz);
1056*d169d70bSTobias Grosser 	int num_params = method->getNumParams();
1057*d169d70bSTobias Grosser 	int first_param = 0;
1058*d169d70bSTobias Grosser 
1059*d169d70bSTobias Grosser 	cname = rename_method(cname);
1060*d169d70bSTobias Grosser 	if (kind == function_kind_member_method)
1061*d169d70bSTobias Grosser 		first_param = 1;
1062*d169d70bSTobias Grosser 
1063*d169d70bSTobias Grosser 	if (is_declaration) {
1064*d169d70bSTobias Grosser 		osprintf(os, "  ");
1065*d169d70bSTobias Grosser 
1066*d169d70bSTobias Grosser 		if (kind == function_kind_static_method)
1067*d169d70bSTobias Grosser 			osprintf(os, "static ");
1068*d169d70bSTobias Grosser 
1069*d169d70bSTobias Grosser 		osprintf(os, "inline ");
1070*d169d70bSTobias Grosser 
1071*d169d70bSTobias Grosser 		if (kind == function_kind_constructor) {
1072*d169d70bSTobias Grosser 			if (is_implicit_conversion(clazz, method))
1073*d169d70bSTobias Grosser 				osprintf(os, "/* implicit */ ");
1074*d169d70bSTobias Grosser 			else
1075*d169d70bSTobias Grosser 				osprintf(os, "explicit ");
1076*d169d70bSTobias Grosser 		}
1077*d169d70bSTobias Grosser 	}
1078*d169d70bSTobias Grosser 
1079*d169d70bSTobias Grosser 	if (kind != function_kind_constructor)
1080*d169d70bSTobias Grosser 		osprintf(os, "%s ", rettype_str.c_str());
1081*d169d70bSTobias Grosser 
1082*d169d70bSTobias Grosser 	if (!is_declaration)
1083*d169d70bSTobias Grosser 		osprintf(os, "%s::", classname.c_str());
1084*d169d70bSTobias Grosser 
1085*d169d70bSTobias Grosser 	if (kind != function_kind_constructor)
1086*d169d70bSTobias Grosser 		osprintf(os, "%s", cname.c_str());
1087*d169d70bSTobias Grosser 	else
1088*d169d70bSTobias Grosser 		osprintf(os, "%s", classname.c_str());
1089*d169d70bSTobias Grosser 
1090*d169d70bSTobias Grosser 	osprintf(os, "(");
1091*d169d70bSTobias Grosser 
1092*d169d70bSTobias Grosser 	for (int i = first_param; i < num_params; ++i) {
1093*d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
1094*d169d70bSTobias Grosser 		QualType type = param->getOriginalType();
1095*d169d70bSTobias Grosser 		string cpptype = type2cpp(type);
1096*d169d70bSTobias Grosser 
1097*d169d70bSTobias Grosser 		if (is_callback(type))
1098*d169d70bSTobias Grosser 			num_params--;
1099*d169d70bSTobias Grosser 
1100*d169d70bSTobias Grosser 		if (keeps(param) || is_string(type) || is_callback(type))
1101*d169d70bSTobias Grosser 			osprintf(os, "const %s &%s", cpptype.c_str(),
1102*d169d70bSTobias Grosser 				 param->getName().str().c_str());
1103*d169d70bSTobias Grosser 		else
1104*d169d70bSTobias Grosser 			osprintf(os, "%s %s", cpptype.c_str(),
1105*d169d70bSTobias Grosser 				 param->getName().str().c_str());
1106*d169d70bSTobias Grosser 
1107*d169d70bSTobias Grosser 		if (i != num_params - 1)
1108*d169d70bSTobias Grosser 			osprintf(os, ", ");
1109*d169d70bSTobias Grosser 	}
1110*d169d70bSTobias Grosser 
1111*d169d70bSTobias Grosser 	osprintf(os, ")");
1112*d169d70bSTobias Grosser 
1113*d169d70bSTobias Grosser 	if (kind == function_kind_member_method)
1114*d169d70bSTobias Grosser 		osprintf(os, " const");
1115*d169d70bSTobias Grosser 
1116*d169d70bSTobias Grosser 	if (is_declaration)
1117*d169d70bSTobias Grosser 		osprintf(os, ";");
1118*d169d70bSTobias Grosser 	osprintf(os, "\n");
1119*d169d70bSTobias Grosser }
1120*d169d70bSTobias Grosser 
1121*d169d70bSTobias Grosser /* Generate the list of argument types for a callback function of
1122*d169d70bSTobias Grosser  * type "type".  If "cpp" is set, then generate the C++ type list, otherwise
1123*d169d70bSTobias Grosser  * the C type list.
1124*d169d70bSTobias Grosser  *
1125*d169d70bSTobias Grosser  * For a callback of type
1126*d169d70bSTobias Grosser  *
1127*d169d70bSTobias Grosser  *      isl_stat (*)(__isl_take isl_map *map, void *user)
1128*d169d70bSTobias Grosser  *
1129*d169d70bSTobias Grosser  * the following C++ argument list is generated:
1130*d169d70bSTobias Grosser  *
1131*d169d70bSTobias Grosser  *      map
1132*d169d70bSTobias Grosser  */
1133*d169d70bSTobias Grosser string cpp_generator::generate_callback_args(QualType type, bool cpp)
1134*d169d70bSTobias Grosser {
1135*d169d70bSTobias Grosser 	std::string type_str;
1136*d169d70bSTobias Grosser 	const FunctionProtoType *callback;
1137*d169d70bSTobias Grosser 	int num_params;
1138*d169d70bSTobias Grosser 
1139*d169d70bSTobias Grosser 	callback = type->getPointeeType()->getAs<FunctionProtoType>();
1140*d169d70bSTobias Grosser 	num_params = callback->getNumArgs();
1141*d169d70bSTobias Grosser 	if (cpp)
1142*d169d70bSTobias Grosser 		num_params--;
1143*d169d70bSTobias Grosser 
1144*d169d70bSTobias Grosser 	for (long i = 0; i < num_params; i++) {
1145*d169d70bSTobias Grosser 		QualType type = callback->getArgType(i);
1146*d169d70bSTobias Grosser 
1147*d169d70bSTobias Grosser 		if (cpp)
1148*d169d70bSTobias Grosser 			type_str += type2cpp(type);
1149*d169d70bSTobias Grosser 		else
1150*d169d70bSTobias Grosser 			type_str += type.getAsString();
1151*d169d70bSTobias Grosser 
1152*d169d70bSTobias Grosser 		if (!cpp)
1153*d169d70bSTobias Grosser 			type_str += "arg_" + ::to_string(i);
1154*d169d70bSTobias Grosser 
1155*d169d70bSTobias Grosser 		if (i != num_params - 1)
1156*d169d70bSTobias Grosser 			type_str += ", ";
1157*d169d70bSTobias Grosser 	}
1158*d169d70bSTobias Grosser 
1159*d169d70bSTobias Grosser 	return type_str;
1160*d169d70bSTobias Grosser }
1161*d169d70bSTobias Grosser 
1162*d169d70bSTobias Grosser /* Generate the full cpp type of a callback function of type "type".
1163*d169d70bSTobias Grosser  *
1164*d169d70bSTobias Grosser  * For a callback of type
1165*d169d70bSTobias Grosser  *
1166*d169d70bSTobias Grosser  *      isl_stat (*)(__isl_take isl_map *map, void *user)
1167*d169d70bSTobias Grosser  *
1168*d169d70bSTobias Grosser  * the following type is generated:
1169*d169d70bSTobias Grosser  *
1170*d169d70bSTobias Grosser  *      std::function<stat(map)>
1171*d169d70bSTobias Grosser  */
1172*d169d70bSTobias Grosser string cpp_generator::generate_callback_type(QualType type)
1173*d169d70bSTobias Grosser {
1174*d169d70bSTobias Grosser 	std::string type_str;
1175*d169d70bSTobias Grosser 	const FunctionProtoType *callback = type->getPointeeType()->getAs<FunctionProtoType>();
1176*d169d70bSTobias Grosser 	QualType return_type = callback->getReturnType();
1177*d169d70bSTobias Grosser 	string rettype_str = type2cpp(return_type);
1178*d169d70bSTobias Grosser 
1179*d169d70bSTobias Grosser 	type_str = "std::function<";
1180*d169d70bSTobias Grosser 	type_str += rettype_str;
1181*d169d70bSTobias Grosser 	type_str += "(";
1182*d169d70bSTobias Grosser 	type_str += generate_callback_args(type, true);
1183*d169d70bSTobias Grosser 	type_str += ")>";
1184*d169d70bSTobias Grosser 
1185*d169d70bSTobias Grosser 	return type_str;
1186*d169d70bSTobias Grosser }
1187*d169d70bSTobias Grosser 
1188*d169d70bSTobias Grosser /* Print the call to the C++ callback function "call", wrapped
1189*d169d70bSTobias Grosser  * for use inside the lambda function that is used as the C callback function,
1190*d169d70bSTobias Grosser  * in the case where checked C++ bindings are being generated.
1191*d169d70bSTobias Grosser  *
1192*d169d70bSTobias Grosser  * In particular, print
1193*d169d70bSTobias Grosser  *
1194*d169d70bSTobias Grosser  *        stat ret = @call@;
1195*d169d70bSTobias Grosser  *        return ret.release();
1196*d169d70bSTobias Grosser  */
1197*d169d70bSTobias Grosser void cpp_generator::print_wrapped_call_checked(ostream &os,
1198*d169d70bSTobias Grosser 	const string &call)
1199*d169d70bSTobias Grosser {
1200*d169d70bSTobias Grosser 	osprintf(os, "    stat ret = %s;\n", call.c_str());
1201*d169d70bSTobias Grosser 	osprintf(os, "    return ret.release();\n");
1202*d169d70bSTobias Grosser }
1203*d169d70bSTobias Grosser 
1204*d169d70bSTobias Grosser /* Print the call to the C++ callback function "call", wrapped
1205*d169d70bSTobias Grosser  * for use inside the lambda function that is used as the C callback function.
1206*d169d70bSTobias Grosser  *
1207*d169d70bSTobias Grosser  * In particular, print
1208*d169d70bSTobias Grosser  *
1209*d169d70bSTobias Grosser  *        ISL_CPP_TRY {
1210*d169d70bSTobias Grosser  *          @call@;
1211*d169d70bSTobias Grosser  *          return isl_stat_ok;
1212*d169d70bSTobias Grosser  *        } ISL_CPP_CATCH_ALL {
1213*d169d70bSTobias Grosser  *          data->eptr = std::current_exception();
1214*d169d70bSTobias Grosser  *          return isl_stat_error;
1215*d169d70bSTobias Grosser  *        }
1216*d169d70bSTobias Grosser  *
1217*d169d70bSTobias Grosser  * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)"
1218*d169d70bSTobias Grosser  * (if exceptions are available).
1219*d169d70bSTobias Grosser  *
1220*d169d70bSTobias Grosser  * If checked C++ bindings are being generated, then
1221*d169d70bSTobias Grosser  * the call is wrapped differently.
1222*d169d70bSTobias Grosser  */
1223*d169d70bSTobias Grosser void cpp_generator::print_wrapped_call(ostream &os, const string &call)
1224*d169d70bSTobias Grosser {
1225*d169d70bSTobias Grosser 	if (checked)
1226*d169d70bSTobias Grosser 		return print_wrapped_call_checked(os, call);
1227*d169d70bSTobias Grosser 
1228*d169d70bSTobias Grosser 	osprintf(os, "    ISL_CPP_TRY {\n");
1229*d169d70bSTobias Grosser 	osprintf(os, "      %s;\n", call.c_str());
1230*d169d70bSTobias Grosser 	osprintf(os, "      return isl_stat_ok;\n");
1231*d169d70bSTobias Grosser 	osprintf(os, "    } ISL_CPP_CATCH_ALL {\n"
1232*d169d70bSTobias Grosser 		     "      data->eptr = std::current_exception();\n");
1233*d169d70bSTobias Grosser 	osprintf(os, "      return isl_stat_error;\n");
1234*d169d70bSTobias Grosser 	osprintf(os, "    }\n");
1235*d169d70bSTobias Grosser }
1236*d169d70bSTobias Grosser 
1237*d169d70bSTobias Grosser /* Print the local variables that are needed for a callback argument,
1238*d169d70bSTobias Grosser  * in particular, print a lambda function that wraps the callback and
1239*d169d70bSTobias Grosser  * a pointer to the actual C++ callback function.
1240*d169d70bSTobias Grosser  *
1241*d169d70bSTobias Grosser  * For a callback of the form
1242*d169d70bSTobias Grosser  *
1243*d169d70bSTobias Grosser  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
1244*d169d70bSTobias Grosser  *
1245*d169d70bSTobias Grosser  * the following lambda function is generated:
1246*d169d70bSTobias Grosser  *
1247*d169d70bSTobias Grosser  *      auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
1248*d169d70bSTobias Grosser  *        auto *data = static_cast<struct fn_data *>(arg_1);
1249*d169d70bSTobias Grosser  *        try {
1250*d169d70bSTobias Grosser  *          stat ret = (*data->func)(manage(arg_0));
1251*d169d70bSTobias Grosser  *          return isl_stat_ok;
1252*d169d70bSTobias Grosser  *        } catch (...) {
1253*d169d70bSTobias Grosser  *          data->eptr = std::current_exception();
1254*d169d70bSTobias Grosser  *          return isl_stat_error;
1255*d169d70bSTobias Grosser  *        }
1256*d169d70bSTobias Grosser  *      };
1257*d169d70bSTobias Grosser  *
1258*d169d70bSTobias Grosser  * The pointer to the std::function C++ callback function is stored in
1259*d169d70bSTobias Grosser  * a fn_data data structure for passing to the C callback function,
1260*d169d70bSTobias Grosser  * along with an std::exception_ptr that is used to store any
1261*d169d70bSTobias Grosser  * exceptions thrown in the C++ callback.
1262*d169d70bSTobias Grosser  *
1263*d169d70bSTobias Grosser  *      struct fn_data {
1264*d169d70bSTobias Grosser  *        const std::function<stat(map)> *func;
1265*d169d70bSTobias Grosser  *        std::exception_ptr eptr;
1266*d169d70bSTobias Grosser  *      } fn_data = { &fn };
1267*d169d70bSTobias Grosser  *
1268*d169d70bSTobias Grosser  * This std::function object represents the actual user
1269*d169d70bSTobias Grosser  * callback function together with the locally captured state at the caller.
1270*d169d70bSTobias Grosser  *
1271*d169d70bSTobias Grosser  * The lambda function is expected to be used as a C callback function
1272*d169d70bSTobias Grosser  * where the lambda itself is provided as the function pointer and
1273*d169d70bSTobias Grosser  * where the user void pointer is a pointer to fn_data.
1274*d169d70bSTobias Grosser  * The std::function object is extracted from the pointer to fn_data
1275*d169d70bSTobias Grosser  * inside the lambda function.
1276*d169d70bSTobias Grosser  *
1277*d169d70bSTobias Grosser  * The std::exception_ptr object is not added to fn_data
1278*d169d70bSTobias Grosser  * if checked C++ bindings are being generated.
1279*d169d70bSTobias Grosser  * The body of the generated lambda function then is as follows:
1280*d169d70bSTobias Grosser  *
1281*d169d70bSTobias Grosser  *        stat ret = (*data->func)(manage(arg_0));
1282*d169d70bSTobias Grosser  *        return isl_stat(ret);
1283*d169d70bSTobias Grosser  */
1284*d169d70bSTobias Grosser void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param)
1285*d169d70bSTobias Grosser {
1286*d169d70bSTobias Grosser 	string pname;
1287*d169d70bSTobias Grosser 	QualType ptype;
1288*d169d70bSTobias Grosser 	string call, c_args, cpp_args, rettype, last_idx;
1289*d169d70bSTobias Grosser 	const FunctionProtoType *callback;
1290*d169d70bSTobias Grosser 	int num_params;
1291*d169d70bSTobias Grosser 
1292*d169d70bSTobias Grosser 	pname = param->getName().str();
1293*d169d70bSTobias Grosser 	ptype = param->getType();
1294*d169d70bSTobias Grosser 
1295*d169d70bSTobias Grosser 	c_args = generate_callback_args(ptype, false);
1296*d169d70bSTobias Grosser 	cpp_args = generate_callback_type(ptype);
1297*d169d70bSTobias Grosser 
1298*d169d70bSTobias Grosser 	callback = ptype->getPointeeType()->getAs<FunctionProtoType>();
1299*d169d70bSTobias Grosser 	rettype = callback->getReturnType().getAsString();
1300*d169d70bSTobias Grosser 	num_params = callback->getNumArgs();
1301*d169d70bSTobias Grosser 
1302*d169d70bSTobias Grosser 	last_idx = ::to_string(num_params - 1);
1303*d169d70bSTobias Grosser 
1304*d169d70bSTobias Grosser 	call = "(*data->func)(";
1305*d169d70bSTobias Grosser 	for (long i = 0; i < num_params - 1; i++) {
1306*d169d70bSTobias Grosser 		call += "manage(arg_" + ::to_string(i) + ")";
1307*d169d70bSTobias Grosser 		if (i != num_params - 2)
1308*d169d70bSTobias Grosser 			call += ", ";
1309*d169d70bSTobias Grosser 	}
1310*d169d70bSTobias Grosser 	call += ")";
1311*d169d70bSTobias Grosser 
1312*d169d70bSTobias Grosser 	osprintf(os, "  struct %s_data {\n", pname.c_str());
1313*d169d70bSTobias Grosser 	osprintf(os, "    const %s *func;\n", cpp_args.c_str());
1314*d169d70bSTobias Grosser 	if (!checked)
1315*d169d70bSTobias Grosser 		osprintf(os, "    std::exception_ptr eptr;\n");
1316*d169d70bSTobias Grosser 	osprintf(os, "  } %s_data = { &%s };\n", pname.c_str(), pname.c_str());
1317*d169d70bSTobias Grosser 	osprintf(os, "  auto %s_lambda = [](%s) -> %s {\n",
1318*d169d70bSTobias Grosser 		 pname.c_str(), c_args.c_str(), rettype.c_str());
1319*d169d70bSTobias Grosser 	osprintf(os,
1320*d169d70bSTobias Grosser 		 "    auto *data = static_cast<struct %s_data *>(arg_%s);\n",
1321*d169d70bSTobias Grosser 		 pname.c_str(), last_idx.c_str());
1322*d169d70bSTobias Grosser 	print_wrapped_call(os, call);
1323*d169d70bSTobias Grosser 	osprintf(os, "  };\n");
1324*d169d70bSTobias Grosser }
1325*d169d70bSTobias Grosser 
1326*d169d70bSTobias Grosser /* An array listing functions that must be renamed and the function name they
1327*d169d70bSTobias Grosser  * should be renamed to. We currently rename functions in case their name would
1328*d169d70bSTobias Grosser  * match a reserved C++ keyword, which is not allowed in C++.
1329*d169d70bSTobias Grosser  */
1330*d169d70bSTobias Grosser static const char *rename_map[][2] = {
1331*d169d70bSTobias Grosser 	{ "union", "unite" },
1332*d169d70bSTobias Grosser };
1333*d169d70bSTobias Grosser 
1334*d169d70bSTobias Grosser /* Rename method "name" in case the method name in the C++ bindings should not
1335*d169d70bSTobias Grosser  * match the name in the C bindings. We do this for example to avoid
1336*d169d70bSTobias Grosser  * C++ keywords.
1337*d169d70bSTobias Grosser  */
1338*d169d70bSTobias Grosser std::string cpp_generator::rename_method(std::string name)
1339*d169d70bSTobias Grosser {
1340*d169d70bSTobias Grosser 	for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++)
1341*d169d70bSTobias Grosser 		if (name.compare(rename_map[i][0]) == 0)
1342*d169d70bSTobias Grosser 			return rename_map[i][1];
1343*d169d70bSTobias Grosser 
1344*d169d70bSTobias Grosser 	return name;
1345*d169d70bSTobias Grosser }
1346*d169d70bSTobias Grosser 
1347*d169d70bSTobias Grosser /* Translate isl class "clazz" to its corresponding C++ type.
1348*d169d70bSTobias Grosser  */
1349*d169d70bSTobias Grosser string cpp_generator::type2cpp(const isl_class &clazz)
1350*d169d70bSTobias Grosser {
1351*d169d70bSTobias Grosser 	return type2cpp(clazz.name);
1352*d169d70bSTobias Grosser }
1353*d169d70bSTobias Grosser 
1354*d169d70bSTobias Grosser /* Translate type string "type_str" to its C++ name counterpart.
1355*d169d70bSTobias Grosser */
1356*d169d70bSTobias Grosser string cpp_generator::type2cpp(string type_str)
1357*d169d70bSTobias Grosser {
1358*d169d70bSTobias Grosser 	return type_str.substr(4);
1359*d169d70bSTobias Grosser }
1360*d169d70bSTobias Grosser 
1361*d169d70bSTobias Grosser /* Translate QualType "type" to its C++ name counterpart.
1362*d169d70bSTobias Grosser  *
1363*d169d70bSTobias Grosser  * An isl_bool return type is translated into "bool",
1364*d169d70bSTobias Grosser  * while an isl_stat is translated into "void".
1365*d169d70bSTobias Grosser  * The exceptional cases are handled through exceptions.
1366*d169d70bSTobias Grosser  * If checked C++ bindings are being generated, then
1367*d169d70bSTobias Grosser  * C++ counterparts of isl_bool and isl_stat need to be used instead.
1368*d169d70bSTobias Grosser  */
1369*d169d70bSTobias Grosser string cpp_generator::type2cpp(QualType type)
1370*d169d70bSTobias Grosser {
1371*d169d70bSTobias Grosser 	if (is_isl_type(type))
1372*d169d70bSTobias Grosser 		return type2cpp(type->getPointeeType().getAsString());
1373*d169d70bSTobias Grosser 
1374*d169d70bSTobias Grosser 	if (is_isl_bool(type))
1375*d169d70bSTobias Grosser 		return checked ? "boolean" : "bool";
1376*d169d70bSTobias Grosser 
1377*d169d70bSTobias Grosser 	if (is_isl_stat(type))
1378*d169d70bSTobias Grosser 		return checked ? "stat" : "void";
1379*d169d70bSTobias Grosser 
1380*d169d70bSTobias Grosser 	if (type->isIntegerType())
1381*d169d70bSTobias Grosser 		return type.getAsString();
1382*d169d70bSTobias Grosser 
1383*d169d70bSTobias Grosser 	if (is_string(type))
1384*d169d70bSTobias Grosser 		return "std::string";
1385*d169d70bSTobias Grosser 
1386*d169d70bSTobias Grosser 	if (is_callback(type))
1387*d169d70bSTobias Grosser 		return generate_callback_type(type);
1388*d169d70bSTobias Grosser 
1389*d169d70bSTobias Grosser 	die("Cannot convert type to C++ type");
1390*d169d70bSTobias Grosser }
1391*d169d70bSTobias Grosser 
1392*d169d70bSTobias Grosser /* Check if "subclass_type" is a subclass of "class_type".
1393*d169d70bSTobias Grosser  */
1394*d169d70bSTobias Grosser bool cpp_generator::is_subclass(QualType subclass_type,
1395*d169d70bSTobias Grosser 	const isl_class &class_type)
1396*d169d70bSTobias Grosser {
1397*d169d70bSTobias Grosser 	std::string type_str = subclass_type->getPointeeType().getAsString();
1398*d169d70bSTobias Grosser 	std::vector<std::string> superclasses;
1399*d169d70bSTobias Grosser 	std::vector<const isl_class *> parents;
1400*d169d70bSTobias Grosser 	std::vector<std::string>::iterator ci;
1401*d169d70bSTobias Grosser 
1402*d169d70bSTobias Grosser 	superclasses = generator::find_superclasses(classes[type_str].type);
1403*d169d70bSTobias Grosser 
1404*d169d70bSTobias Grosser 	for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
1405*d169d70bSTobias Grosser 		parents.push_back(&classes[*ci]);
1406*d169d70bSTobias Grosser 
1407*d169d70bSTobias Grosser 	while (!parents.empty()) {
1408*d169d70bSTobias Grosser 		const isl_class *candidate = parents.back();
1409*d169d70bSTobias Grosser 
1410*d169d70bSTobias Grosser 		parents.pop_back();
1411*d169d70bSTobias Grosser 
1412*d169d70bSTobias Grosser 		if (&class_type == candidate)
1413*d169d70bSTobias Grosser 			return true;
1414*d169d70bSTobias Grosser 
1415*d169d70bSTobias Grosser 		superclasses = generator::find_superclasses(candidate->type);
1416*d169d70bSTobias Grosser 
1417*d169d70bSTobias Grosser 		for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
1418*d169d70bSTobias Grosser 			parents.push_back(&classes[*ci]);
1419*d169d70bSTobias Grosser 	}
1420*d169d70bSTobias Grosser 
1421*d169d70bSTobias Grosser 	return false;
1422*d169d70bSTobias Grosser }
1423*d169d70bSTobias Grosser 
1424*d169d70bSTobias Grosser /* Check if "cons" is an implicit conversion constructor of class "clazz".
1425*d169d70bSTobias Grosser  *
1426*d169d70bSTobias Grosser  * An implicit conversion constructor is generated in case "cons" has a single
1427*d169d70bSTobias Grosser  * parameter, where the parameter type is a subclass of the class that is
1428*d169d70bSTobias Grosser  * currently being generated.
1429*d169d70bSTobias Grosser  */
1430*d169d70bSTobias Grosser bool cpp_generator::is_implicit_conversion(const isl_class &clazz,
1431*d169d70bSTobias Grosser 	FunctionDecl *cons)
1432*d169d70bSTobias Grosser {
1433*d169d70bSTobias Grosser 	ParmVarDecl *param = cons->getParamDecl(0);
1434*d169d70bSTobias Grosser 	QualType type = param->getOriginalType();
1435*d169d70bSTobias Grosser 
1436*d169d70bSTobias Grosser 	int num_params = cons->getNumParams();
1437*d169d70bSTobias Grosser 	if (num_params != 1)
1438*d169d70bSTobias Grosser 		return false;
1439*d169d70bSTobias Grosser 
1440*d169d70bSTobias Grosser 	if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz))
1441*d169d70bSTobias Grosser 		return true;
1442*d169d70bSTobias Grosser 
1443*d169d70bSTobias Grosser 	return false;
1444*d169d70bSTobias Grosser }
1445*d169d70bSTobias Grosser 
1446*d169d70bSTobias Grosser /* Get kind of "method" in "clazz".
1447*d169d70bSTobias Grosser  *
1448*d169d70bSTobias Grosser  * Given the declaration of a static or member method, returns its kind.
1449*d169d70bSTobias Grosser  */
1450*d169d70bSTobias Grosser cpp_generator::function_kind cpp_generator::get_method_kind(
1451*d169d70bSTobias Grosser 	const isl_class &clazz, FunctionDecl *method)
1452*d169d70bSTobias Grosser {
1453*d169d70bSTobias Grosser 	if (is_static(clazz, method))
1454*d169d70bSTobias Grosser 		return function_kind_static_method;
1455*d169d70bSTobias Grosser 	else
1456*d169d70bSTobias Grosser 		return function_kind_member_method;
1457*d169d70bSTobias Grosser }
1458