1d169d70bSTobias Grosser /*
2d169d70bSTobias Grosser  * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
3d169d70bSTobias Grosser  *
4d169d70bSTobias Grosser  * Redistribution and use in source and binary forms, with or without
5d169d70bSTobias Grosser  * modification, are permitted provided that the following conditions
6d169d70bSTobias Grosser  * are met:
7d169d70bSTobias Grosser  *
8d169d70bSTobias Grosser  *    1. Redistributions of source code must retain the above copyright
9d169d70bSTobias Grosser  *       notice, this list of conditions and the following disclaimer.
10d169d70bSTobias Grosser  *
11d169d70bSTobias Grosser  *    2. Redistributions in binary form must reproduce the above
12d169d70bSTobias Grosser  *       copyright notice, this list of conditions and the following
13d169d70bSTobias Grosser  *       disclaimer in the documentation and/or other materials provided
14d169d70bSTobias Grosser  *       with the distribution.
15d169d70bSTobias Grosser  *
16d169d70bSTobias Grosser  * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY
17d169d70bSTobias Grosser  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d169d70bSTobias Grosser  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19d169d70bSTobias Grosser  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR
20d169d70bSTobias Grosser  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21d169d70bSTobias Grosser  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22d169d70bSTobias Grosser  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23d169d70bSTobias Grosser  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24d169d70bSTobias Grosser  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25d169d70bSTobias Grosser  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26d169d70bSTobias Grosser  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27d169d70bSTobias Grosser  *
28d169d70bSTobias Grosser  * The views and conclusions contained in the software and documentation
29d169d70bSTobias Grosser  * are those of the authors and should not be interpreted as
30d169d70bSTobias Grosser  * representing official policies, either expressed or implied, of
31d169d70bSTobias Grosser  * Tobias Grosser.
32d169d70bSTobias Grosser  */
33d169d70bSTobias Grosser 
34d169d70bSTobias Grosser #include <cstdarg>
35d169d70bSTobias Grosser #include <cstdio>
36d169d70bSTobias Grosser #include <iostream>
37d169d70bSTobias Grosser #include <map>
38d169d70bSTobias Grosser #include <sstream>
39d169d70bSTobias Grosser #include <string>
40d169d70bSTobias Grosser #include <vector>
41d169d70bSTobias Grosser 
42d169d70bSTobias Grosser #include "cpp.h"
43d169d70bSTobias Grosser #include "isl_config.h"
44d169d70bSTobias Grosser 
45d169d70bSTobias Grosser /* Print string formatted according to "fmt" to ostream "os".
46d169d70bSTobias Grosser  *
47d169d70bSTobias Grosser  * This osprintf method allows us to use printf style formatting constructs when
48d169d70bSTobias Grosser  * writing to an ostream.
49d169d70bSTobias Grosser  */
50*e8227804SMichael Kruse static void osprintf(ostream &os, const char *format, va_list arguments)
51d169d70bSTobias Grosser {
52*e8227804SMichael Kruse 	va_list copy;
53d169d70bSTobias Grosser 	char *string_pointer;
54d169d70bSTobias Grosser 	size_t size;
55d169d70bSTobias Grosser 
56*e8227804SMichael Kruse 	va_copy(copy, arguments);
57*e8227804SMichael Kruse 	size = vsnprintf(NULL, 0, format, copy);
58d169d70bSTobias Grosser 	string_pointer = new char[size + 1];
59*e8227804SMichael Kruse 	va_end(copy);
60d169d70bSTobias Grosser 	vsnprintf(string_pointer, size + 1, format, arguments);
61d169d70bSTobias Grosser 	os << string_pointer;
62d169d70bSTobias Grosser 	delete[] string_pointer;
63d169d70bSTobias Grosser }
64d169d70bSTobias Grosser 
65*e8227804SMichael Kruse /* Print string formatted according to "fmt" to ostream "os".
66*e8227804SMichael Kruse  *
67*e8227804SMichael Kruse  * This osprintf method allows us to use printf style formatting constructs when
68*e8227804SMichael Kruse  * writing to an ostream.
69*e8227804SMichael Kruse  */
70*e8227804SMichael Kruse static void osprintf(ostream &os, const char *format, ...)
71*e8227804SMichael Kruse {
72*e8227804SMichael Kruse 	va_list arguments;
73*e8227804SMichael Kruse 
74*e8227804SMichael Kruse 	va_start(arguments, format);
75*e8227804SMichael Kruse 	osprintf(os, format, arguments);
76*e8227804SMichael Kruse 	va_end(arguments);
77*e8227804SMichael Kruse }
78*e8227804SMichael Kruse 
79*e8227804SMichael Kruse /* Print string formatted according to "fmt" to ostream "os"
80*e8227804SMichael Kruse  * with the given indentation.
81*e8227804SMichael Kruse  *
82*e8227804SMichael Kruse  * This osprintf method allows us to use printf style formatting constructs when
83*e8227804SMichael Kruse  * writing to an ostream.
84*e8227804SMichael Kruse  */
85*e8227804SMichael Kruse static void osprintf(ostream &os, int indent, const char *format, ...)
86*e8227804SMichael Kruse {
87*e8227804SMichael Kruse 	va_list arguments;
88*e8227804SMichael Kruse 
89*e8227804SMichael Kruse 	osprintf(os, "%*s", indent, " ");
90*e8227804SMichael Kruse 	va_start(arguments, format);
91*e8227804SMichael Kruse 	osprintf(os, format, arguments);
92*e8227804SMichael Kruse 	va_end(arguments);
93*e8227804SMichael Kruse }
94*e8227804SMichael Kruse 
95d169d70bSTobias Grosser /* Convert "l" to a string.
96d169d70bSTobias Grosser  */
97d169d70bSTobias Grosser static std::string to_string(long l)
98d169d70bSTobias Grosser {
99d169d70bSTobias Grosser 	std::ostringstream strm;
100d169d70bSTobias Grosser 	strm << l;
101d169d70bSTobias Grosser 	return strm.str();
102d169d70bSTobias Grosser }
103d169d70bSTobias Grosser 
104d169d70bSTobias Grosser /* Generate a cpp interface based on the extracted types and functions.
105d169d70bSTobias Grosser  *
106d169d70bSTobias Grosser  * Print first a set of forward declarations for all isl wrapper
107d169d70bSTobias Grosser  * classes, then the declarations of the classes, and at the end all
108d169d70bSTobias Grosser  * implementations.
109d169d70bSTobias Grosser  *
110d169d70bSTobias Grosser  * If checked C++ bindings are being generated,
111d169d70bSTobias Grosser  * then wrap them in a namespace to avoid conflicts
112d169d70bSTobias Grosser  * with the default C++ bindings (with automatic checks using exceptions).
113d169d70bSTobias Grosser  */
114d169d70bSTobias Grosser void cpp_generator::generate()
115d169d70bSTobias Grosser {
116d169d70bSTobias Grosser 	ostream &os = cout;
117d169d70bSTobias Grosser 
118d169d70bSTobias Grosser 	osprintf(os, "\n");
119d169d70bSTobias Grosser 	osprintf(os, "namespace isl {\n\n");
120d169d70bSTobias Grosser 	if (checked)
121d169d70bSTobias Grosser 		osprintf(os, "namespace checked {\n\n");
122d169d70bSTobias Grosser 
123d169d70bSTobias Grosser 	print_forward_declarations(os);
124d169d70bSTobias Grosser 	osprintf(os, "\n");
125d169d70bSTobias Grosser 	print_declarations(os);
126d169d70bSTobias Grosser 	osprintf(os, "\n");
127d169d70bSTobias Grosser 	print_implementations(os);
128d169d70bSTobias Grosser 
129d169d70bSTobias Grosser 	if (checked)
130d169d70bSTobias Grosser 		osprintf(os, "} // namespace checked\n");
131d169d70bSTobias Grosser 	osprintf(os, "} // namespace isl\n");
132d169d70bSTobias Grosser }
133d169d70bSTobias Grosser 
134d169d70bSTobias Grosser /* Print forward declarations for all classes to "os".
135d169d70bSTobias Grosser */
136d169d70bSTobias Grosser void cpp_generator::print_forward_declarations(ostream &os)
137d169d70bSTobias Grosser {
138d169d70bSTobias Grosser 	map<string, isl_class>::iterator ci;
139d169d70bSTobias Grosser 
140d169d70bSTobias Grosser 	osprintf(os, "// forward declarations\n");
141d169d70bSTobias Grosser 
142d169d70bSTobias Grosser 	for (ci = classes.begin(); ci != classes.end(); ++ci)
143d169d70bSTobias Grosser 		print_class_forward_decl(os, ci->second);
144d169d70bSTobias Grosser }
145d169d70bSTobias Grosser 
146d169d70bSTobias Grosser /* Print all declarations to "os".
147d169d70bSTobias Grosser  */
148d169d70bSTobias Grosser void cpp_generator::print_declarations(ostream &os)
149d169d70bSTobias Grosser {
150d169d70bSTobias Grosser 	map<string, isl_class>::iterator ci;
151d169d70bSTobias Grosser 	bool first = true;
152d169d70bSTobias Grosser 
153d169d70bSTobias Grosser 	for (ci = classes.begin(); ci != classes.end(); ++ci) {
154d169d70bSTobias Grosser 		if (first)
155d169d70bSTobias Grosser 			first = false;
156d169d70bSTobias Grosser 		else
157d169d70bSTobias Grosser 			osprintf(os, "\n");
158d169d70bSTobias Grosser 
159d169d70bSTobias Grosser 		print_class(os, ci->second);
160d169d70bSTobias Grosser 	}
161d169d70bSTobias Grosser }
162d169d70bSTobias Grosser 
163d169d70bSTobias Grosser /* Print all implementations to "os".
164d169d70bSTobias Grosser  */
165d169d70bSTobias Grosser void cpp_generator::print_implementations(ostream &os)
166d169d70bSTobias Grosser {
167d169d70bSTobias Grosser 	map<string, isl_class>::iterator ci;
168d169d70bSTobias Grosser 	bool first = true;
169d169d70bSTobias Grosser 
170d169d70bSTobias Grosser 	for (ci = classes.begin(); ci != classes.end(); ++ci) {
171d169d70bSTobias Grosser 		if (first)
172d169d70bSTobias Grosser 			first = false;
173d169d70bSTobias Grosser 		else
174d169d70bSTobias Grosser 			osprintf(os, "\n");
175d169d70bSTobias Grosser 
176d169d70bSTobias Grosser 		print_class_impl(os, ci->second);
177d169d70bSTobias Grosser 	}
178d169d70bSTobias Grosser }
179d169d70bSTobias Grosser 
180*e8227804SMichael Kruse /* If "clazz" is a subclass that is based on a type function,
181*e8227804SMichael Kruse  * then introduce a "type" field that holds the value of the type
182*e8227804SMichael Kruse  * corresponding to the subclass and make the fields of the class
183*e8227804SMichael Kruse  * accessible to the "isa" and "as" methods of the (immediate) superclass.
184*e8227804SMichael Kruse  * In particular, "isa" needs access to the type field itself,
185*e8227804SMichael Kruse  * while "as" needs access to the private constructor.
186*e8227804SMichael Kruse  * In case of the "isa" method, all instances are made friends
187*e8227804SMichael Kruse  * to avoid access right confusion.
188*e8227804SMichael Kruse  */
189*e8227804SMichael Kruse void cpp_generator::print_subclass_type(ostream &os, const isl_class &clazz)
190*e8227804SMichael Kruse {
191*e8227804SMichael Kruse 	std::string cppstring = type2cpp(clazz);
192*e8227804SMichael Kruse 	std::string super;
193*e8227804SMichael Kruse 	const char *cppname = cppstring.c_str();
194*e8227804SMichael Kruse 	const char *supername;
195*e8227804SMichael Kruse 
196*e8227804SMichael Kruse 	if (!clazz.is_type_subclass())
197*e8227804SMichael Kruse 		return;
198*e8227804SMichael Kruse 
199*e8227804SMichael Kruse 	super = type2cpp(clazz.superclass_name);
200*e8227804SMichael Kruse 	supername = super.c_str();
201*e8227804SMichael Kruse 	osprintf(os, "  template <class T>\n");
202*e8227804SMichael Kruse 	osprintf(os, "  friend %s %s::isa() const;\n",
203*e8227804SMichael Kruse 		isl_bool2cpp().c_str(), supername);
204*e8227804SMichael Kruse 	osprintf(os, "  friend %s %s::as<%s>() const;\n",
205*e8227804SMichael Kruse 		cppname, supername, cppname);
206*e8227804SMichael Kruse 	osprintf(os, "  static const auto type = %s;\n",
207*e8227804SMichael Kruse 		clazz.subclass_name.c_str());
208*e8227804SMichael Kruse }
209*e8227804SMichael Kruse 
210d169d70bSTobias Grosser /* Print declarations for class "clazz" to "os".
211*e8227804SMichael Kruse  *
212*e8227804SMichael Kruse  * If "clazz" is a subclass based on a type function,
213*e8227804SMichael Kruse  * then it is made to inherit from the (immediate) superclass and
214*e8227804SMichael Kruse  * a "type" attribute is added for use in the "as" and "isa"
215*e8227804SMichael Kruse  * methods of the superclass.
216*e8227804SMichael Kruse  *
217*e8227804SMichael Kruse  * Conversely, if "clazz" is a superclass with a type function,
218*e8227804SMichael Kruse  * then declare those "as" and "isa" methods.
219*e8227804SMichael Kruse  *
220*e8227804SMichael Kruse  * The pointer to the isl object is only added for classes that
221*e8227804SMichael Kruse  * are not subclasses, since subclasses refer to the same isl object.
222d169d70bSTobias Grosser  */
223d169d70bSTobias Grosser void cpp_generator::print_class(ostream &os, const isl_class &clazz)
224d169d70bSTobias Grosser {
225d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
226d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
227d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
228d169d70bSTobias Grosser 
229d169d70bSTobias Grosser 	osprintf(os, "// declarations for isl::%s\n", cppname);
230d169d70bSTobias Grosser 
231d169d70bSTobias Grosser 	print_class_factory_decl(os, clazz);
232d169d70bSTobias Grosser 	osprintf(os, "\n");
233*e8227804SMichael Kruse 	osprintf(os, "class %s ", cppname);
234*e8227804SMichael Kruse 	if (clazz.is_type_subclass())
235*e8227804SMichael Kruse 		osprintf(os, ": public %s ",
236*e8227804SMichael Kruse 			type2cpp(clazz.superclass_name).c_str());
237*e8227804SMichael Kruse 	osprintf(os, "{\n");
238*e8227804SMichael Kruse 	print_subclass_type(os, clazz);
239d169d70bSTobias Grosser 	print_class_factory_decl(os, clazz, "  friend ");
240d169d70bSTobias Grosser 	osprintf(os, "\n");
241*e8227804SMichael Kruse 	osprintf(os, "protected:\n");
242*e8227804SMichael Kruse 	if (!clazz.is_type_subclass()) {
243d169d70bSTobias Grosser 		osprintf(os, "  %s *ptr = nullptr;\n", name);
244d169d70bSTobias Grosser 		osprintf(os, "\n");
245*e8227804SMichael Kruse 	}
246*e8227804SMichael Kruse 	print_protected_constructors_decl(os, clazz);
247d169d70bSTobias Grosser 	osprintf(os, "\n");
248d169d70bSTobias Grosser 	osprintf(os, "public:\n");
249d169d70bSTobias Grosser 	print_public_constructors_decl(os, clazz);
250d169d70bSTobias Grosser 	print_constructors_decl(os, clazz);
251d169d70bSTobias Grosser 	print_copy_assignment_decl(os, clazz);
252d169d70bSTobias Grosser 	print_destructor_decl(os, clazz);
253d169d70bSTobias Grosser 	print_ptr_decl(os, clazz);
254*e8227804SMichael Kruse 	print_downcast_decl(os, clazz);
255*e8227804SMichael Kruse 	print_ctx_decl(os);
256d169d70bSTobias Grosser 	osprintf(os, "\n");
257*e8227804SMichael Kruse 	print_persistent_callbacks_decl(os, clazz);
258d169d70bSTobias Grosser 	print_methods_decl(os, clazz);
259*e8227804SMichael Kruse 	print_set_enums_decl(os, clazz);
260d169d70bSTobias Grosser 
261d169d70bSTobias Grosser 	osprintf(os, "};\n");
262d169d70bSTobias Grosser }
263d169d70bSTobias Grosser 
264d169d70bSTobias Grosser /* Print forward declaration of class "clazz" to "os".
265d169d70bSTobias Grosser  */
266d169d70bSTobias Grosser void cpp_generator::print_class_forward_decl(ostream &os,
267d169d70bSTobias Grosser 	const isl_class &clazz)
268d169d70bSTobias Grosser {
269d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
270d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
271d169d70bSTobias Grosser 
272d169d70bSTobias Grosser 	osprintf(os, "class %s;\n", cppname);
273d169d70bSTobias Grosser }
274d169d70bSTobias Grosser 
275d169d70bSTobias Grosser /* Print global factory functions to "os".
276d169d70bSTobias Grosser  *
277d169d70bSTobias Grosser  * Each class has two global factory functions:
278d169d70bSTobias Grosser  *
279d169d70bSTobias Grosser  * 	set manage(__isl_take isl_set *ptr);
280d169d70bSTobias Grosser  * 	set manage_copy(__isl_keep isl_set *ptr);
281d169d70bSTobias Grosser  *
282d169d70bSTobias Grosser  * A user can construct isl C++ objects from a raw pointer and indicate whether
283d169d70bSTobias Grosser  * they intend to take the ownership of the object or not through these global
284d169d70bSTobias Grosser  * factory functions. This ensures isl object creation is very explicit and
285d169d70bSTobias Grosser  * pointers are not converted by accident. Thanks to overloading, manage() and
286d169d70bSTobias Grosser  * manage_copy() can be called on any isl raw pointer and the corresponding
287d169d70bSTobias Grosser  * object is automatically created, without the user having to choose the right
288d169d70bSTobias Grosser  * isl object type.
289*e8227804SMichael Kruse  *
290*e8227804SMichael Kruse  * For a subclass based on a type function, no factory functions
291*e8227804SMichael Kruse  * are introduced because they share the C object type with
292*e8227804SMichael Kruse  * the superclass.
293d169d70bSTobias Grosser  */
294d169d70bSTobias Grosser void cpp_generator::print_class_factory_decl(ostream &os,
295d169d70bSTobias Grosser 	const isl_class &clazz, const std::string &prefix)
296d169d70bSTobias Grosser {
297d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
298d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
299d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
300d169d70bSTobias Grosser 
301*e8227804SMichael Kruse 	if (clazz.is_type_subclass())
302*e8227804SMichael Kruse 		return;
303*e8227804SMichael Kruse 
304d169d70bSTobias Grosser 	os << prefix;
305d169d70bSTobias Grosser 	osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name);
306d169d70bSTobias Grosser 	os << prefix;
307d169d70bSTobias Grosser 	osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n",
308d169d70bSTobias Grosser 		cppname, name);
309d169d70bSTobias Grosser }
310d169d70bSTobias Grosser 
311*e8227804SMichael Kruse /* Print declarations of protected constructors for class "clazz" to "os".
312d169d70bSTobias Grosser  *
313*e8227804SMichael Kruse  * Each class has currently one protected constructor:
314d169d70bSTobias Grosser  *
315d169d70bSTobias Grosser  * 	1) Constructor from a plain isl_* C pointer
316d169d70bSTobias Grosser  *
317d169d70bSTobias Grosser  * Example:
318d169d70bSTobias Grosser  *
319d169d70bSTobias Grosser  * 	set(__isl_take isl_set *ptr);
320d169d70bSTobias Grosser  *
321*e8227804SMichael Kruse  * The raw pointer constructor is kept protected. Object creation is only
322d169d70bSTobias Grosser  * possible through manage() or manage_copy().
323d169d70bSTobias Grosser  */
324*e8227804SMichael Kruse void cpp_generator::print_protected_constructors_decl(ostream &os,
325d169d70bSTobias Grosser 	const isl_class &clazz)
326d169d70bSTobias Grosser {
327d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
328d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
329d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
330d169d70bSTobias Grosser 
331d169d70bSTobias Grosser 	osprintf(os, "  inline explicit %s(__isl_take %s *ptr);\n", cppname,
332d169d70bSTobias Grosser 		 name);
333d169d70bSTobias Grosser }
334d169d70bSTobias Grosser 
335d169d70bSTobias Grosser /* Print declarations of public constructors for class "clazz" to "os".
336d169d70bSTobias Grosser  *
337d169d70bSTobias Grosser  * Each class currently has two public constructors:
338d169d70bSTobias Grosser  *
339d169d70bSTobias Grosser  * 	1) A default constructor
340d169d70bSTobias Grosser  * 	2) A copy constructor
341d169d70bSTobias Grosser  *
342d169d70bSTobias Grosser  * Example:
343d169d70bSTobias Grosser  *
344d169d70bSTobias Grosser  *	set();
345d169d70bSTobias Grosser  *	set(const set &set);
346d169d70bSTobias Grosser  */
347d169d70bSTobias Grosser void cpp_generator::print_public_constructors_decl(ostream &os,
348d169d70bSTobias Grosser 	const isl_class &clazz)
349d169d70bSTobias Grosser {
350d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
351d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
352d169d70bSTobias Grosser 	osprintf(os, "  inline /* implicit */ %s();\n", cppname);
353d169d70bSTobias Grosser 
354d169d70bSTobias Grosser 	osprintf(os, "  inline /* implicit */ %s(const %s &obj);\n",
355d169d70bSTobias Grosser 		 cppname, cppname);
356d169d70bSTobias Grosser }
357d169d70bSTobias Grosser 
358*e8227804SMichael Kruse /* Print declarations for "method" in class "clazz" to "os".
359*e8227804SMichael Kruse  *
360*e8227804SMichael Kruse  * "kind" specifies the kind of method that should be generated.
361*e8227804SMichael Kruse  *
362*e8227804SMichael Kruse  * "convert" specifies which of the method arguments should
363*e8227804SMichael Kruse  * be automatically converted.
364*e8227804SMichael Kruse  */
365*e8227804SMichael Kruse template <>
366*e8227804SMichael Kruse void cpp_generator::print_method<cpp_generator::decl>(ostream &os,
367*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *method, function_kind kind,
368*e8227804SMichael Kruse 	const std::vector<bool> &convert)
369*e8227804SMichael Kruse {
370*e8227804SMichael Kruse 	string name = clazz.method_name(method);
371*e8227804SMichael Kruse 
372*e8227804SMichael Kruse 	print_named_method_decl(os, clazz, method, name, kind, convert);
373*e8227804SMichael Kruse }
374*e8227804SMichael Kruse 
375*e8227804SMichael Kruse /* Print declarations for "method" in class "clazz" to "os",
376*e8227804SMichael Kruse  * without any argument conversions.
377*e8227804SMichael Kruse  *
378*e8227804SMichael Kruse  * "kind" specifies the kind of method that should be generated.
379*e8227804SMichael Kruse  */
380*e8227804SMichael Kruse template <>
381*e8227804SMichael Kruse void cpp_generator::print_method<cpp_generator::decl>(ostream &os,
382*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *method, function_kind kind)
383*e8227804SMichael Kruse {
384*e8227804SMichael Kruse 	print_method<decl>(os, clazz,method, kind, {});
385*e8227804SMichael Kruse }
386*e8227804SMichael Kruse 
387d169d70bSTobias Grosser /* Print declarations for constructors for class "class" to "os".
388d169d70bSTobias Grosser  *
389d169d70bSTobias Grosser  * For each isl function that is marked as __isl_constructor,
390d169d70bSTobias Grosser  * add a corresponding C++ constructor.
391d169d70bSTobias Grosser  *
392d169d70bSTobias Grosser  * Example:
393d169d70bSTobias Grosser  *
394d169d70bSTobias Grosser  * 	inline /\* implicit *\/ union_set(basic_set bset);
395d169d70bSTobias Grosser  * 	inline /\* implicit *\/ union_set(set set);
396d169d70bSTobias Grosser  * 	inline explicit val(ctx ctx, long i);
397d169d70bSTobias Grosser  * 	inline explicit val(ctx ctx, const std::string &str);
398d169d70bSTobias Grosser  */
399d169d70bSTobias Grosser void cpp_generator::print_constructors_decl(ostream &os,
400d169d70bSTobias Grosser        const isl_class &clazz)
401d169d70bSTobias Grosser {
402*e8227804SMichael Kruse 	function_set::const_iterator in;
403*e8227804SMichael Kruse 	const function_set &constructors = clazz.constructors;
404d169d70bSTobias Grosser 
405d169d70bSTobias Grosser 	for (in = constructors.begin(); in != constructors.end(); ++in) {
406d169d70bSTobias Grosser 		FunctionDecl *cons = *in;
407d169d70bSTobias Grosser 
408*e8227804SMichael Kruse 		print_method<decl>(os, clazz, cons, function_kind_constructor);
409d169d70bSTobias Grosser 	}
410d169d70bSTobias Grosser }
411d169d70bSTobias Grosser 
412d169d70bSTobias Grosser /* Print declarations of copy assignment operator for class "clazz"
413d169d70bSTobias Grosser  * to "os".
414d169d70bSTobias Grosser  *
415d169d70bSTobias Grosser  * Each class has one assignment operator.
416d169d70bSTobias Grosser  *
417d169d70bSTobias Grosser  * 	isl:set &set::operator=(set obj)
418d169d70bSTobias Grosser  *
419d169d70bSTobias Grosser  */
420d169d70bSTobias Grosser void cpp_generator::print_copy_assignment_decl(ostream &os,
421d169d70bSTobias Grosser 	const isl_class &clazz)
422d169d70bSTobias Grosser {
423d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
424d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
425d169d70bSTobias Grosser 
426d169d70bSTobias Grosser 	osprintf(os, "  inline %s &operator=(%s obj);\n", cppname, cppname);
427d169d70bSTobias Grosser }
428d169d70bSTobias Grosser 
429d169d70bSTobias Grosser /* Print declaration of destructor for class "clazz" to "os".
430*e8227804SMichael Kruse  *
431*e8227804SMichael Kruse  * No explicit destructor is needed for type based subclasses.
432d169d70bSTobias Grosser  */
433d169d70bSTobias Grosser void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz)
434d169d70bSTobias Grosser {
435d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
436d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
437d169d70bSTobias Grosser 
438*e8227804SMichael Kruse 	if (clazz.is_type_subclass())
439*e8227804SMichael Kruse 		return;
440*e8227804SMichael Kruse 
441d169d70bSTobias Grosser 	osprintf(os, "  inline ~%s();\n", cppname);
442d169d70bSTobias Grosser }
443d169d70bSTobias Grosser 
444d169d70bSTobias Grosser /* Print declaration of pointer functions for class "clazz" to "os".
445*e8227804SMichael Kruse  * Since type based subclasses share the pointer with their superclass,
446*e8227804SMichael Kruse  * they can also reuse these functions from the superclass.
447d169d70bSTobias Grosser  *
448d169d70bSTobias Grosser  * To obtain a raw pointer three functions are provided:
449d169d70bSTobias Grosser  *
450d169d70bSTobias Grosser  * 	1) __isl_give isl_set *copy()
451d169d70bSTobias Grosser  *
452d169d70bSTobias Grosser  * 	  Returns a pointer to a _copy_ of the internal object
453d169d70bSTobias Grosser  *
454d169d70bSTobias Grosser  * 	2) __isl_keep isl_set *get()
455d169d70bSTobias Grosser  *
456d169d70bSTobias Grosser  * 	  Returns a pointer to the internal object
457d169d70bSTobias Grosser  *
458d169d70bSTobias Grosser  * 	3) __isl_give isl_set *release()
459d169d70bSTobias Grosser  *
460d169d70bSTobias Grosser  * 	  Returns a pointer to the internal object and resets the
461d169d70bSTobias Grosser  * 	  internal pointer to nullptr.
462d169d70bSTobias Grosser  *
463d169d70bSTobias Grosser  * We also provide functionality to explicitly check if a pointer is
464d169d70bSTobias Grosser  * currently managed by this object.
465d169d70bSTobias Grosser  *
466d169d70bSTobias Grosser  * 	4) bool is_null()
467d169d70bSTobias Grosser  *
468d169d70bSTobias Grosser  * 	  Check if the current object is a null pointer.
469d169d70bSTobias Grosser  *
470d169d70bSTobias Grosser  * The functions get() and release() model the value_ptr proposed in
471d169d70bSTobias Grosser  * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
472d169d70bSTobias Grosser  * The copy() function is an extension to allow the user to explicitly
473d169d70bSTobias Grosser  * copy the underlying object.
474d169d70bSTobias Grosser  *
475d169d70bSTobias Grosser  * Also generate a declaration to delete copy() for r-values, for
476d169d70bSTobias Grosser  * r-values release() should be used to avoid unnecessary copies.
477d169d70bSTobias Grosser  */
478d169d70bSTobias Grosser void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz)
479d169d70bSTobias Grosser {
480d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
481d169d70bSTobias Grosser 
482*e8227804SMichael Kruse 	if (clazz.is_type_subclass())
483*e8227804SMichael Kruse 		return;
484*e8227804SMichael Kruse 
485d169d70bSTobias Grosser 	osprintf(os, "  inline __isl_give %s *copy() const &;\n", name);
486d169d70bSTobias Grosser 	osprintf(os, "  inline __isl_give %s *copy() && = delete;\n", name);
487d169d70bSTobias Grosser 	osprintf(os, "  inline __isl_keep %s *get() const;\n", name);
488d169d70bSTobias Grosser 	osprintf(os, "  inline __isl_give %s *release();\n", name);
489d169d70bSTobias Grosser 	osprintf(os, "  inline bool is_null() const;\n");
490d169d70bSTobias Grosser }
491d169d70bSTobias Grosser 
492*e8227804SMichael Kruse /* Print a template declaration with given indentation
493*e8227804SMichael Kruse  * for the "isa_type" method that ensures it is only enabled
494*e8227804SMichael Kruse  * when called with a template argument
495*e8227804SMichael Kruse  * that represents a type that is equal to that
496*e8227804SMichael Kruse  * of the return type of the type function of "super".
497*e8227804SMichael Kruse  * In particular, "isa_type" gets called from "isa"
498*e8227804SMichael Kruse  * with as template argument the type of the "type" field
499*e8227804SMichael Kruse  * of the subclass.
500*e8227804SMichael Kruse  * The check ensures that this subclass is in fact a direct subclass
501*e8227804SMichael Kruse  * of "super".
502d169d70bSTobias Grosser  */
503*e8227804SMichael Kruse void cpp_generator::print_isa_type_template(ostream &os, int indent,
504*e8227804SMichael Kruse 	const isl_class &super)
505d169d70bSTobias Grosser {
506*e8227804SMichael Kruse 	osprintf(os, indent,
507*e8227804SMichael Kruse 		"template <typename T,\n");
508*e8227804SMichael Kruse 	osprintf(os, indent,
509*e8227804SMichael Kruse 		"        typename = typename std::enable_if<std::is_same<\n");
510*e8227804SMichael Kruse 	osprintf(os, indent,
511*e8227804SMichael Kruse 		"                const decltype(%s(NULL)),\n",
512*e8227804SMichael Kruse 		super.fn_type->getNameAsString().c_str());
513*e8227804SMichael Kruse 	osprintf(os, indent,
514*e8227804SMichael Kruse 		"                const T>::value>::type>\n");
515*e8227804SMichael Kruse }
516*e8227804SMichael Kruse 
517*e8227804SMichael Kruse /* Print declarations for the "as" and "isa" methods, if "clazz"
518*e8227804SMichael Kruse  * is a superclass with a type function.
519*e8227804SMichael Kruse  *
520*e8227804SMichael Kruse  * "isa" checks whether an object is of a given subclass type.
521*e8227804SMichael Kruse  * "isa_type" does the same, but gets passed the value of the type field
522*e8227804SMichael Kruse  * of the subclass as a function argument and the type of this field
523*e8227804SMichael Kruse  * as a template argument.
524*e8227804SMichael Kruse  * "as" tries to cast an object to a given subclass type, returning
525*e8227804SMichael Kruse  * an invalid object if the object is not of the given type.
526*e8227804SMichael Kruse  */
527*e8227804SMichael Kruse void cpp_generator::print_downcast_decl(ostream &os, const isl_class &clazz)
528*e8227804SMichael Kruse {
529*e8227804SMichael Kruse 	if (!clazz.fn_type)
530*e8227804SMichael Kruse 		return;
531*e8227804SMichael Kruse 
532*e8227804SMichael Kruse 	osprintf(os, "private:\n");
533*e8227804SMichael Kruse 	print_isa_type_template(os, 2, clazz);
534*e8227804SMichael Kruse 	osprintf(os, "  inline %s isa_type(T subtype) const;\n",
535*e8227804SMichael Kruse 		isl_bool2cpp().c_str());
536*e8227804SMichael Kruse 	osprintf(os, "public:\n");
537*e8227804SMichael Kruse 	osprintf(os, "  template <class T> inline %s isa() const;\n",
538*e8227804SMichael Kruse 		isl_bool2cpp().c_str());
539*e8227804SMichael Kruse 	osprintf(os, "  template <class T> inline T as() const;\n");
540*e8227804SMichael Kruse }
541*e8227804SMichael Kruse 
542*e8227804SMichael Kruse /* Print the declaration of the ctx method.
543*e8227804SMichael Kruse  */
544*e8227804SMichael Kruse void cpp_generator::print_ctx_decl(ostream &os)
545*e8227804SMichael Kruse {
546*e8227804SMichael Kruse 	std::string ns = isl_namespace();
547*e8227804SMichael Kruse 
548*e8227804SMichael Kruse 	osprintf(os, "  inline %sctx ctx() const;\n", ns.c_str());
549*e8227804SMichael Kruse }
550*e8227804SMichael Kruse 
551*e8227804SMichael Kruse /* Add a space to the return type "type" if needed,
552*e8227804SMichael Kruse  * i.e., if it is not the type of a pointer.
553*e8227804SMichael Kruse  */
554*e8227804SMichael Kruse static string add_space_to_return_type(const string &type)
555*e8227804SMichael Kruse {
556*e8227804SMichael Kruse 	if (type[type.size() - 1] == '*')
557*e8227804SMichael Kruse 		return type;
558*e8227804SMichael Kruse 	return type + " ";
559*e8227804SMichael Kruse }
560*e8227804SMichael Kruse 
561*e8227804SMichael Kruse /* Print the prototype of the static inline method that is used
562*e8227804SMichael Kruse  * as the C callback of "clazz" set by "method" to "os".
563*e8227804SMichael Kruse  */
564*e8227804SMichael Kruse void cpp_generator::print_persistent_callback_prototype(ostream &os,
565*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *method, bool is_declaration)
566*e8227804SMichael Kruse {
567*e8227804SMichael Kruse 	string callback_name, rettype, c_args;
568*e8227804SMichael Kruse 	ParmVarDecl *param = persistent_callback_arg(method);
569*e8227804SMichael Kruse 	const FunctionProtoType *callback;
570*e8227804SMichael Kruse 	QualType ptype;
571*e8227804SMichael Kruse 	string classname;
572*e8227804SMichael Kruse 
573*e8227804SMichael Kruse 	ptype = param->getType();
574*e8227804SMichael Kruse 	callback = extract_prototype(ptype);
575*e8227804SMichael Kruse 
576*e8227804SMichael Kruse 	rettype = callback->getReturnType().getAsString();
577*e8227804SMichael Kruse 	rettype = add_space_to_return_type(rettype);
578*e8227804SMichael Kruse 	callback_name = clazz.persistent_callback_name(method);
579*e8227804SMichael Kruse 	c_args = generate_callback_args(ptype, false);
580*e8227804SMichael Kruse 
581*e8227804SMichael Kruse 	if (!is_declaration)
582*e8227804SMichael Kruse 		classname = type2cpp(clazz) + "::";
583*e8227804SMichael Kruse 
584*e8227804SMichael Kruse 	osprintf(os, "%s%s%s(%s)",
585*e8227804SMichael Kruse 		 rettype.c_str(), classname.c_str(),
586*e8227804SMichael Kruse 		 callback_name.c_str(), c_args.c_str());
587*e8227804SMichael Kruse }
588*e8227804SMichael Kruse 
589*e8227804SMichael Kruse /* Print the prototype of the method for setting the callback function
590*e8227804SMichael Kruse  * of "clazz" set by "method" to "os".
591*e8227804SMichael Kruse  */
592*e8227804SMichael Kruse void cpp_generator::print_persistent_callback_setter_prototype(ostream &os,
593*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *method, bool is_declaration)
594*e8227804SMichael Kruse {
595*e8227804SMichael Kruse 	string classname, callback_name, cpptype;
596*e8227804SMichael Kruse 	ParmVarDecl *param = persistent_callback_arg(method);
597*e8227804SMichael Kruse 
598*e8227804SMichael Kruse 	if (!is_declaration)
599*e8227804SMichael Kruse 		classname = type2cpp(clazz) + "::";
600*e8227804SMichael Kruse 
601*e8227804SMichael Kruse 	cpptype = type2cpp(param->getOriginalType());
602*e8227804SMichael Kruse 	callback_name = clazz.persistent_callback_name(method);
603*e8227804SMichael Kruse 	osprintf(os, "void %sset_%s_data(const %s &%s)",
604*e8227804SMichael Kruse 		classname.c_str(), callback_name.c_str(), cpptype.c_str(),
605*e8227804SMichael Kruse 		param->getName().str().c_str());
606*e8227804SMichael Kruse }
607*e8227804SMichael Kruse 
608*e8227804SMichael Kruse /* Given a function "method" for setting a "clazz" persistent callback,
609*e8227804SMichael Kruse  * print the fields that are needed for marshalling the callback to "os".
610*e8227804SMichael Kruse  *
611*e8227804SMichael Kruse  * In particular, print
612*e8227804SMichael Kruse  * - the declaration of a data structure for storing the C++ callback function
613*e8227804SMichael Kruse  * - a shared pointer to such a data structure
614*e8227804SMichael Kruse  * - the declaration of a static inline method
615*e8227804SMichael Kruse  *   for use as the C callback function
616*e8227804SMichael Kruse  * - the declaration of a private method for setting the callback function
617*e8227804SMichael Kruse  */
618*e8227804SMichael Kruse void cpp_generator::print_persistent_callback_data(ostream &os,
619*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *method)
620*e8227804SMichael Kruse {
621*e8227804SMichael Kruse 	string callback_name;
622*e8227804SMichael Kruse 	ParmVarDecl *param = persistent_callback_arg(method);
623*e8227804SMichael Kruse 
624*e8227804SMichael Kruse 	callback_name = clazz.persistent_callback_name(method);
625*e8227804SMichael Kruse 	print_callback_data_decl(os, param, callback_name);
626*e8227804SMichael Kruse 	osprintf(os, ";\n");
627*e8227804SMichael Kruse 	osprintf(os, "  std::shared_ptr<%s_data> %s_data;\n",
628*e8227804SMichael Kruse 		callback_name.c_str(), callback_name.c_str());
629*e8227804SMichael Kruse 	osprintf(os, "  static inline ");
630*e8227804SMichael Kruse 	print_persistent_callback_prototype(os, clazz, method, true);
631*e8227804SMichael Kruse 	osprintf(os, ";\n");
632*e8227804SMichael Kruse 	osprintf(os, "  inline ");
633*e8227804SMichael Kruse 	print_persistent_callback_setter_prototype(os, clazz, method, true);
634*e8227804SMichael Kruse 	osprintf(os, ";\n");
635*e8227804SMichael Kruse }
636*e8227804SMichael Kruse 
637*e8227804SMichael Kruse /* Print declarations needed for the persistent callbacks of "clazz".
638*e8227804SMichael Kruse  *
639*e8227804SMichael Kruse  * In particular, if there are any persistent callbacks, then
640*e8227804SMichael Kruse  * print a private method for copying callback data from
641*e8227804SMichael Kruse  * one object to another,
642*e8227804SMichael Kruse  * private data for keeping track of the persistent callbacks and
643*e8227804SMichael Kruse  * public methods for setting the persistent callbacks.
644*e8227804SMichael Kruse  */
645*e8227804SMichael Kruse void cpp_generator::print_persistent_callbacks_decl(ostream &os,
646*e8227804SMichael Kruse        const isl_class &clazz)
647*e8227804SMichael Kruse {
648*e8227804SMichael Kruse 	std::string cppstring = type2cpp(clazz);
649*e8227804SMichael Kruse 	const char *cppname = cppstring.c_str();
650*e8227804SMichael Kruse 	set<FunctionDecl *>::const_iterator in;
651*e8227804SMichael Kruse 	const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
652*e8227804SMichael Kruse 
653*e8227804SMichael Kruse 	if (!clazz.has_persistent_callbacks())
654*e8227804SMichael Kruse 		return;
655*e8227804SMichael Kruse 
656*e8227804SMichael Kruse 	osprintf(os, "private:\n");
657*e8227804SMichael Kruse 	osprintf(os, "  inline %s &copy_callbacks(const %s &obj);\n",
658*e8227804SMichael Kruse 		cppname, cppname);
659*e8227804SMichael Kruse 	for (in = callbacks.begin(); in != callbacks.end(); ++in)
660*e8227804SMichael Kruse 		print_persistent_callback_data(os, clazz, *in);
661*e8227804SMichael Kruse 
662*e8227804SMichael Kruse 	osprintf(os, "public:\n");
663*e8227804SMichael Kruse 	for (in = callbacks.begin(); in != callbacks.end(); ++in)
664*e8227804SMichael Kruse 		print_method<decl>(os, clazz, *in, function_kind_member_method);
665d169d70bSTobias Grosser }
666d169d70bSTobias Grosser 
667d169d70bSTobias Grosser /* Print declarations for methods in class "clazz" to "os".
668d169d70bSTobias Grosser  */
669d169d70bSTobias Grosser void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz)
670d169d70bSTobias Grosser {
671*e8227804SMichael Kruse 	map<string, function_set >::const_iterator it;
672d169d70bSTobias Grosser 
673d169d70bSTobias Grosser 	for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
6746145b11cSTobias Grosser 		print_method_group_decl(os, clazz, it->second);
675d169d70bSTobias Grosser }
676d169d70bSTobias Grosser 
677*e8227804SMichael Kruse /* Print a declaration for a method "name" in "clazz" derived
678*e8227804SMichael Kruse  * from "fd", which sets an enum, to "os".
679*e8227804SMichael Kruse  *
680*e8227804SMichael Kruse  * The last argument is removed because it is replaced by
681*e8227804SMichael Kruse  * a break-up into several methods.
682*e8227804SMichael Kruse  */
683*e8227804SMichael Kruse void cpp_generator::print_set_enum_decl(ostream &os, const isl_class &clazz,
684*e8227804SMichael Kruse 	FunctionDecl *fd, const string &name)
685*e8227804SMichael Kruse {
686*e8227804SMichael Kruse 	int n = fd->getNumParams();
687*e8227804SMichael Kruse 
688*e8227804SMichael Kruse 	print_method_header(os, clazz, fd, name, n - 1, true,
689*e8227804SMichael Kruse 				function_kind_member_method);
690*e8227804SMichael Kruse }
691*e8227804SMichael Kruse 
692*e8227804SMichael Kruse /* Print declarations for the methods in "clazz" derived from "fd",
693*e8227804SMichael Kruse  * which sets an enum, to "os".
694*e8227804SMichael Kruse  *
695*e8227804SMichael Kruse  * A method is generated for each value in the enum, setting
696*e8227804SMichael Kruse  * the enum to that value.
697*e8227804SMichael Kruse  */
698*e8227804SMichael Kruse void cpp_generator::print_set_enums_decl(ostream &os, const isl_class &clazz,
699*e8227804SMichael Kruse 	FunctionDecl *fd)
700*e8227804SMichael Kruse {
701*e8227804SMichael Kruse 	vector<set_enum>::const_iterator it;
702*e8227804SMichael Kruse 	const vector<set_enum> &set_enums = clazz.set_enums.at(fd);
703*e8227804SMichael Kruse 
704*e8227804SMichael Kruse 	for (it = set_enums.begin(); it != set_enums.end(); ++it)
705*e8227804SMichael Kruse 		print_set_enum_decl(os, clazz, fd, it->method_name);
706*e8227804SMichael Kruse }
707*e8227804SMichael Kruse 
708*e8227804SMichael Kruse /* Print declarations for methods in "clazz" derived from functions
709*e8227804SMichael Kruse  * that set an enum, to "os".
710*e8227804SMichael Kruse  */
711*e8227804SMichael Kruse void cpp_generator::print_set_enums_decl(ostream &os, const isl_class &clazz)
712*e8227804SMichael Kruse {
713*e8227804SMichael Kruse 	map<FunctionDecl *, vector<set_enum> >::const_iterator it;
714*e8227804SMichael Kruse 
715*e8227804SMichael Kruse 	for (it = clazz.set_enums.begin(); it != clazz.set_enums.end(); ++it)
716*e8227804SMichael Kruse 		print_set_enums_decl(os, clazz, it->first);
717*e8227804SMichael Kruse }
718*e8227804SMichael Kruse 
719*e8227804SMichael Kruse /* Print a declaration for the "get" method "fd" in class "clazz",
720*e8227804SMichael Kruse  * using a name that includes the "get_" prefix, to "os".
721*e8227804SMichael Kruse  */
722*e8227804SMichael Kruse template<>
723*e8227804SMichael Kruse void cpp_generator::print_get_method<cpp_generator::decl>(ostream &os,
724*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *fd)
725*e8227804SMichael Kruse {
726*e8227804SMichael Kruse 	function_kind kind = function_kind_member_method;
727*e8227804SMichael Kruse 	string base = clazz.base_method_name(fd);
728*e8227804SMichael Kruse 
729*e8227804SMichael Kruse 	print_named_method_decl(os, clazz, fd, base, kind);
730*e8227804SMichael Kruse }
731*e8227804SMichael Kruse 
732*e8227804SMichael Kruse /* Update "convert" to reflect the next combination of automatic conversions
733*e8227804SMichael Kruse  * for the arguments of "fd",
734*e8227804SMichael Kruse  * returning false if there are no more combinations.
735*e8227804SMichael Kruse  *
736*e8227804SMichael Kruse  * In particular, find the last argument for which an automatic
737*e8227804SMichael Kruse  * conversion function is available mapping to the type of this argument and
738*e8227804SMichael Kruse  * that is not already marked for conversion.
739*e8227804SMichael Kruse  * Mark this argument, if any, for conversion and clear the markings
740*e8227804SMichael Kruse  * of all subsequent arguments.
741*e8227804SMichael Kruse  * Repeated calls to this method therefore run through
742*e8227804SMichael Kruse  * all possible combinations.
743*e8227804SMichael Kruse  *
744*e8227804SMichael Kruse  * Note that the first function argument is never considered
745*e8227804SMichael Kruse  * for automatic conversion since this is the argument
746*e8227804SMichael Kruse  * from which the isl_ctx used in the conversion is extracted.
747*e8227804SMichael Kruse  */
748*e8227804SMichael Kruse bool cpp_generator::next_variant(FunctionDecl *fd, std::vector<bool> &convert)
749*e8227804SMichael Kruse {
750*e8227804SMichael Kruse 	size_t n = convert.size();
751*e8227804SMichael Kruse 
752*e8227804SMichael Kruse 	for (int i = n - 1; i >= 1; --i) {
753*e8227804SMichael Kruse 		ParmVarDecl *param = fd->getParamDecl(i);
754*e8227804SMichael Kruse 		const Type *type = param->getOriginalType().getTypePtr();
755*e8227804SMichael Kruse 
756*e8227804SMichael Kruse 		if (conversions.count(type) == 0)
757*e8227804SMichael Kruse 			continue;
758*e8227804SMichael Kruse 		if (convert[i])
759*e8227804SMichael Kruse 			continue;
760*e8227804SMichael Kruse 		convert[i] = true;
761*e8227804SMichael Kruse 		for (size_t j = i + 1; j < n; ++j)
762*e8227804SMichael Kruse 			convert[j] = false;
763*e8227804SMichael Kruse 		return true;
764*e8227804SMichael Kruse 	}
765*e8227804SMichael Kruse 
766*e8227804SMichael Kruse 	return false;
767*e8227804SMichael Kruse }
768*e8227804SMichael Kruse 
769*e8227804SMichael Kruse /* Print a declaration or definition for method "fd" in class "clazz"
770*e8227804SMichael Kruse  * to "os".
771*e8227804SMichael Kruse  *
772*e8227804SMichael Kruse  * For methods that are identified as "get" methods, also
773*e8227804SMichael Kruse  * print a declaration or definition for the method
774*e8227804SMichael Kruse  * using a name that includes the "get_" prefix.
775*e8227804SMichael Kruse  *
776*e8227804SMichael Kruse  * If the generated method is an object method, then check
777*e8227804SMichael Kruse  * whether any of its arguments can be automatically converted
778*e8227804SMichael Kruse  * from something else, and, if so, generate a method
779*e8227804SMichael Kruse  * for each combination of converted arguments.
780*e8227804SMichael Kruse  */
781*e8227804SMichael Kruse template <enum cpp_generator::method_part part>
782*e8227804SMichael Kruse void cpp_generator::print_method_variants(ostream &os, const isl_class &clazz,
783*e8227804SMichael Kruse 	FunctionDecl *fd)
784*e8227804SMichael Kruse {
785*e8227804SMichael Kruse 	function_kind kind = get_method_kind(clazz, fd);
786*e8227804SMichael Kruse 	std::vector<bool> convert(fd->getNumParams());
787*e8227804SMichael Kruse 
788*e8227804SMichael Kruse 	print_method<part>(os, clazz, fd, kind);
789*e8227804SMichael Kruse 	if (clazz.is_get_method(fd))
790*e8227804SMichael Kruse 		print_get_method<part>(os, clazz, fd);
791*e8227804SMichael Kruse 	if (kind == function_kind_member_method)
792*e8227804SMichael Kruse 		while (next_variant(fd, convert))
793*e8227804SMichael Kruse 			print_method<part>(os, clazz, fd, kind, convert);
794*e8227804SMichael Kruse }
795*e8227804SMichael Kruse 
7966145b11cSTobias Grosser /* Print declarations for methods "methods" in class "clazz" to "os".
797d169d70bSTobias Grosser  */
798d169d70bSTobias Grosser void cpp_generator::print_method_group_decl(ostream &os, const isl_class &clazz,
799*e8227804SMichael Kruse 	const function_set &methods)
800d169d70bSTobias Grosser {
801*e8227804SMichael Kruse 	function_set::const_iterator it;
802d169d70bSTobias Grosser 
803*e8227804SMichael Kruse 	for (it = methods.begin(); it != methods.end(); ++it)
804*e8227804SMichael Kruse 		print_method_variants<decl>(os, clazz, *it);
805d169d70bSTobias Grosser }
806d169d70bSTobias Grosser 
807*e8227804SMichael Kruse /* Print a declaration for a method called "name" in class "clazz"
808*e8227804SMichael Kruse  * derived from "fd" to "os".
809d169d70bSTobias Grosser  *
810d169d70bSTobias Grosser  * "kind" specifies the kind of method that should be generated.
811*e8227804SMichael Kruse  *
812*e8227804SMichael Kruse  * "convert" specifies which of the method arguments should
813*e8227804SMichael Kruse  * be automatically converted.
814d169d70bSTobias Grosser  */
815*e8227804SMichael Kruse void cpp_generator::print_named_method_decl(ostream &os, const isl_class &clazz,
816*e8227804SMichael Kruse 	FunctionDecl *fd, const string &name, function_kind kind,
817*e8227804SMichael Kruse 	const std::vector<bool> &convert)
818d169d70bSTobias Grosser {
819*e8227804SMichael Kruse 	print_named_method_header(os, clazz, fd, name, true, kind, convert);
820d169d70bSTobias Grosser }
821d169d70bSTobias Grosser 
822d169d70bSTobias Grosser /* Print implementations for class "clazz" to "os".
823d169d70bSTobias Grosser  */
824d169d70bSTobias Grosser void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
825d169d70bSTobias Grosser {
826d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
827d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
828d169d70bSTobias Grosser 
829*e8227804SMichael Kruse 	osprintf(os, "// implementations for isl::%s", cppname);
830d169d70bSTobias Grosser 
831d169d70bSTobias Grosser 	print_class_factory_impl(os, clazz);
832d169d70bSTobias Grosser 	print_public_constructors_impl(os, clazz);
833*e8227804SMichael Kruse 	print_protected_constructors_impl(os, clazz);
834d169d70bSTobias Grosser 	print_constructors_impl(os, clazz);
835d169d70bSTobias Grosser 	print_copy_assignment_impl(os, clazz);
836d169d70bSTobias Grosser 	print_destructor_impl(os, clazz);
837d169d70bSTobias Grosser 	print_ptr_impl(os, clazz);
838*e8227804SMichael Kruse 	print_downcast_impl(os, clazz);
839*e8227804SMichael Kruse 	print_ctx_impl(os, clazz);
840*e8227804SMichael Kruse 	print_persistent_callbacks_impl(os, clazz);
841d169d70bSTobias Grosser 	print_methods_impl(os, clazz);
842*e8227804SMichael Kruse 	print_set_enums_impl(os, clazz);
843*e8227804SMichael Kruse 	print_stream_insertion(os, clazz);
844d169d70bSTobias Grosser }
845d169d70bSTobias Grosser 
846d169d70bSTobias Grosser /* Print code for throwing an exception corresponding to the last error
847*e8227804SMichael Kruse  * that occurred on "saved_ctx".
848*e8227804SMichael Kruse  * This assumes that a valid isl::ctx is available in the "saved_ctx" variable,
849d169d70bSTobias Grosser  * e.g., through a prior call to print_save_ctx.
850d169d70bSTobias Grosser  */
851d169d70bSTobias Grosser static void print_throw_last_error(ostream &os)
852d169d70bSTobias Grosser {
853*e8227804SMichael Kruse 	osprintf(os, "    exception::throw_last_error(saved_ctx);\n");
854*e8227804SMichael Kruse }
855*e8227804SMichael Kruse 
856*e8227804SMichael Kruse /* Print code with the given indentation
857*e8227804SMichael Kruse  * for throwing an exception_invalid with the given message.
858*e8227804SMichael Kruse  */
859*e8227804SMichael Kruse static void print_throw_invalid(ostream &os, int indent, const char *msg)
860*e8227804SMichael Kruse {
861*e8227804SMichael Kruse 	osprintf(os, indent,
862*e8227804SMichael Kruse 		"exception::throw_invalid(\"%s\", __FILE__, __LINE__);\n", msg);
863d169d70bSTobias Grosser }
864d169d70bSTobias Grosser 
865d169d70bSTobias Grosser /* Print code for throwing an exception on NULL input.
866d169d70bSTobias Grosser  */
867d169d70bSTobias Grosser static void print_throw_NULL_input(ostream &os)
868d169d70bSTobias Grosser {
869*e8227804SMichael Kruse 	print_throw_invalid(os, 4, "NULL input");
870*e8227804SMichael Kruse }
871*e8227804SMichael Kruse 
872*e8227804SMichael Kruse /* Print code with the given indentation
873*e8227804SMichael Kruse  * for acting on an invalid error with message "msg".
874*e8227804SMichael Kruse  * In particular, throw an exception_invalid.
875*e8227804SMichael Kruse  * In the checked C++ bindings, isl_die is called instead with the code
876*e8227804SMichael Kruse  * in "checked_code".
877*e8227804SMichael Kruse  */
878*e8227804SMichael Kruse void cpp_generator::print_invalid(ostream &os, int indent, const char *msg,
879*e8227804SMichael Kruse 	const char *checked_code)
880*e8227804SMichael Kruse {
881*e8227804SMichael Kruse 	if (checked)
882*e8227804SMichael Kruse 		osprintf(os, indent,
883*e8227804SMichael Kruse 			"isl_die(ctx().get(), isl_error_invalid, "
884*e8227804SMichael Kruse 			"\"%s\", %s);\n", msg, checked_code);
885*e8227804SMichael Kruse 	else
886*e8227804SMichael Kruse 		print_throw_invalid(os, indent, msg);
887*e8227804SMichael Kruse }
888*e8227804SMichael Kruse 
889*e8227804SMichael Kruse /* Print an operator for inserting objects of "class"
890*e8227804SMichael Kruse  * into an output stream.
891*e8227804SMichael Kruse  *
892*e8227804SMichael Kruse  * Unless checked C++ bindings are being generated,
893*e8227804SMichael Kruse  * the operator requires its argument to be non-NULL.
894*e8227804SMichael Kruse  * An exception is thrown if anything went wrong during the printing.
895*e8227804SMichael Kruse  * During this printing, isl is made not to print any error message
896*e8227804SMichael Kruse  * because the error message is included in the exception.
897*e8227804SMichael Kruse  *
898*e8227804SMichael Kruse  * If checked C++ bindings are being generated and anything went wrong,
899*e8227804SMichael Kruse  * then record this failure in the output stream.
900*e8227804SMichael Kruse  */
901*e8227804SMichael Kruse void cpp_generator::print_stream_insertion(ostream &os, const isl_class &clazz)
902*e8227804SMichael Kruse {
903*e8227804SMichael Kruse 	const char *name = clazz.name.c_str();
904*e8227804SMichael Kruse 	std::string cppstring = type2cpp(clazz);
905*e8227804SMichael Kruse 	const char *cppname = cppstring.c_str();
906*e8227804SMichael Kruse 
907*e8227804SMichael Kruse 	if (!clazz.fn_to_str)
908*e8227804SMichael Kruse 		return;
909*e8227804SMichael Kruse 
910*e8227804SMichael Kruse 	osprintf(os, "\n");
911*e8227804SMichael Kruse 	osprintf(os, "inline std::ostream &operator<<(std::ostream &os, ");
912*e8227804SMichael Kruse 	osprintf(os, "const %s &obj)\n", cppname);
913*e8227804SMichael Kruse 	osprintf(os, "{\n");
914*e8227804SMichael Kruse 	print_check_ptr_start(os, clazz, "obj.get()");
915*e8227804SMichael Kruse 	osprintf(os, "  char *str = %s_to_str(obj.get());\n", name);
916*e8227804SMichael Kruse 	print_check_ptr_end(os, "str");
917*e8227804SMichael Kruse 	if (checked) {
918*e8227804SMichael Kruse 		osprintf(os, "  if (!str) {\n");
919*e8227804SMichael Kruse 		osprintf(os, "    os.setstate(std::ios_base::badbit);\n");
920*e8227804SMichael Kruse 		osprintf(os, "    return os;\n");
921*e8227804SMichael Kruse 		osprintf(os, "  }\n");
922*e8227804SMichael Kruse 	}
923*e8227804SMichael Kruse 	osprintf(os, "  os << str;\n");
924*e8227804SMichael Kruse 	osprintf(os, "  free(str);\n");
925*e8227804SMichael Kruse 	osprintf(os, "  return os;\n");
926*e8227804SMichael Kruse 	osprintf(os, "}\n");
927d169d70bSTobias Grosser }
928d169d70bSTobias Grosser 
92926269d34STobias Grosser /* Print code that checks that "ptr" is not NULL at input.
93026269d34STobias Grosser  *
93126269d34STobias Grosser  * Omit the check if checked C++ bindings are being generated.
93226269d34STobias Grosser  */
93326269d34STobias Grosser void cpp_generator::print_check_ptr(ostream &os, const char *ptr)
93426269d34STobias Grosser {
93526269d34STobias Grosser 	if (checked)
93626269d34STobias Grosser 		return;
93726269d34STobias Grosser 
93826269d34STobias Grosser 	osprintf(os, "  if (!%s)\n", ptr);
93926269d34STobias Grosser 	print_throw_NULL_input(os);
94026269d34STobias Grosser }
94126269d34STobias Grosser 
94226269d34STobias Grosser /* Print code that checks that "ptr" is not NULL at input and
94326269d34STobias Grosser  * that saves a copy of the isl_ctx of "ptr" for a later check.
94426269d34STobias Grosser  *
94526269d34STobias Grosser  * Omit the check if checked C++ bindings are being generated.
94626269d34STobias Grosser  */
94726269d34STobias Grosser void cpp_generator::print_check_ptr_start(ostream &os, const isl_class &clazz,
94826269d34STobias Grosser 	const char *ptr)
94926269d34STobias Grosser {
95026269d34STobias Grosser 	if (checked)
95126269d34STobias Grosser 		return;
95226269d34STobias Grosser 
95326269d34STobias Grosser 	print_check_ptr(os, ptr);
954*e8227804SMichael Kruse 	osprintf(os, "  auto saved_ctx = %s_get_ctx(%s);\n",
955*e8227804SMichael Kruse 		clazz.name.c_str(), ptr);
95626269d34STobias Grosser 	print_on_error_continue(os);
95726269d34STobias Grosser }
95826269d34STobias Grosser 
95926269d34STobias Grosser /* Print code that checks that "ptr" is not NULL at the end.
96026269d34STobias Grosser  * A copy of the isl_ctx is expected to have been saved by
96126269d34STobias Grosser  * code generated by print_check_ptr_start.
96226269d34STobias Grosser  *
96326269d34STobias Grosser  * Omit the check if checked C++ bindings are being generated.
96426269d34STobias Grosser  */
96526269d34STobias Grosser void cpp_generator::print_check_ptr_end(ostream &os, const char *ptr)
96626269d34STobias Grosser {
96726269d34STobias Grosser 	if (checked)
96826269d34STobias Grosser 		return;
96926269d34STobias Grosser 
97026269d34STobias Grosser 	osprintf(os, "  if (!%s)\n", ptr);
97126269d34STobias Grosser 	print_throw_last_error(os);
97226269d34STobias Grosser }
97326269d34STobias Grosser 
974d169d70bSTobias Grosser /* Print implementation of global factory functions to "os".
975d169d70bSTobias Grosser  *
976d169d70bSTobias Grosser  * Each class has two global factory functions:
977d169d70bSTobias Grosser  *
978d169d70bSTobias Grosser  * 	set manage(__isl_take isl_set *ptr);
979d169d70bSTobias Grosser  * 	set manage_copy(__isl_keep isl_set *ptr);
980d169d70bSTobias Grosser  *
981d169d70bSTobias Grosser  * Unless checked C++ bindings are being generated,
982d169d70bSTobias Grosser  * both functions require the argument to be non-NULL.
983d169d70bSTobias Grosser  * An exception is thrown if anything went wrong during the copying
984d169d70bSTobias Grosser  * in manage_copy.
985d169d70bSTobias Grosser  * During the copying, isl is made not to print any error message
986d169d70bSTobias Grosser  * because the error message is included in the exception.
987*e8227804SMichael Kruse  *
988*e8227804SMichael Kruse  * For a subclass based on a type function, no factory functions
989*e8227804SMichael Kruse  * are introduced because they share the C object type with
990*e8227804SMichael Kruse  * the superclass.
991d169d70bSTobias Grosser  */
992d169d70bSTobias Grosser void cpp_generator::print_class_factory_impl(ostream &os,
993d169d70bSTobias Grosser 	const isl_class &clazz)
994d169d70bSTobias Grosser {
995d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
996d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
997d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
998d169d70bSTobias Grosser 
999*e8227804SMichael Kruse 	if (clazz.is_type_subclass())
1000*e8227804SMichael Kruse 		return;
1001*e8227804SMichael Kruse 
1002*e8227804SMichael Kruse 	osprintf(os, "\n");
1003d169d70bSTobias Grosser 	osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
100426269d34STobias Grosser 	print_check_ptr(os, "ptr");
1005d169d70bSTobias Grosser 	osprintf(os, "  return %s(ptr);\n", cppname);
1006d169d70bSTobias Grosser 	osprintf(os, "}\n");
1007d169d70bSTobias Grosser 
1008d169d70bSTobias Grosser 	osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
1009d169d70bSTobias Grosser 		name);
101026269d34STobias Grosser 	print_check_ptr_start(os, clazz, "ptr");
1011d169d70bSTobias Grosser 	osprintf(os, "  ptr = %s_copy(ptr);\n", name);
101226269d34STobias Grosser 	print_check_ptr_end(os, "ptr");
1013d169d70bSTobias Grosser 	osprintf(os, "  return %s(ptr);\n", cppname);
1014d169d70bSTobias Grosser 	osprintf(os, "}\n");
1015d169d70bSTobias Grosser }
1016d169d70bSTobias Grosser 
1017*e8227804SMichael Kruse /* Print implementations of protected constructors for class "clazz" to "os".
1018*e8227804SMichael Kruse  *
1019*e8227804SMichael Kruse  * The pointer to the isl object is either initialized directly or
1020*e8227804SMichael Kruse  * through the (immediate) superclass.
1021d169d70bSTobias Grosser  */
1022*e8227804SMichael Kruse void cpp_generator::print_protected_constructors_impl(ostream &os,
1023d169d70bSTobias Grosser 	const isl_class &clazz)
1024d169d70bSTobias Grosser {
1025d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
1026d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
1027d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
1028*e8227804SMichael Kruse 	bool subclass = clazz.is_type_subclass();
1029d169d70bSTobias Grosser 
1030*e8227804SMichael Kruse 	osprintf(os, "\n");
1031*e8227804SMichael Kruse 	osprintf(os, "%s::%s(__isl_take %s *ptr)\n", cppname, cppname, name);
1032*e8227804SMichael Kruse 	if (subclass)
1033*e8227804SMichael Kruse 		osprintf(os, "    : %s(ptr) {}\n",
1034*e8227804SMichael Kruse 			type2cpp(clazz.superclass_name).c_str());
1035*e8227804SMichael Kruse 	else
1036*e8227804SMichael Kruse 		osprintf(os, "    : ptr(ptr) {}\n");
1037d169d70bSTobias Grosser }
1038d169d70bSTobias Grosser 
1039d169d70bSTobias Grosser /* Print implementations of public constructors for class "clazz" to "os".
1040d169d70bSTobias Grosser  *
1041*e8227804SMichael Kruse  * The pointer to the isl object is either initialized directly or
1042*e8227804SMichael Kruse  * through the (immediate) superclass.
1043*e8227804SMichael Kruse  *
1044*e8227804SMichael Kruse  * If the class has any persistent callbacks, then copy them
1045*e8227804SMichael Kruse  * from the original object in the copy constructor.
1046*e8227804SMichael Kruse  * If the class is a subclass, then the persistent callbacks
1047*e8227804SMichael Kruse  * are assumed to be copied by the copy constructor of the superclass.
1048*e8227804SMichael Kruse  *
1049d169d70bSTobias Grosser  * Throw an exception from the copy constructor if anything went wrong
1050*e8227804SMichael Kruse  * during the copying or if the input is NULL, if any copying is performed.
1051d169d70bSTobias Grosser  * During the copying, isl is made not to print any error message
1052d169d70bSTobias Grosser  * because the error message is included in the exception.
1053d169d70bSTobias Grosser  * No exceptions are thrown if checked C++ bindings
1054d169d70bSTobias Grosser  * are being generated,
1055d169d70bSTobias Grosser  */
1056d169d70bSTobias Grosser void cpp_generator::print_public_constructors_impl(ostream &os,
1057d169d70bSTobias Grosser 	const isl_class &clazz)
1058d169d70bSTobias Grosser {
1059d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
1060*e8227804SMichael Kruse 	std::string super;
1061d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
1062*e8227804SMichael Kruse 	bool subclass = clazz.is_type_subclass();
1063d169d70bSTobias Grosser 
1064*e8227804SMichael Kruse 	osprintf(os, "\n");
1065*e8227804SMichael Kruse 	if (subclass)
1066*e8227804SMichael Kruse 		super = type2cpp(clazz.superclass_name);
1067*e8227804SMichael Kruse 	osprintf(os, "%s::%s()\n", cppname, cppname);
1068*e8227804SMichael Kruse 	if (subclass)
1069*e8227804SMichael Kruse 		osprintf(os, "    : %s() {}\n\n", super.c_str());
1070*e8227804SMichael Kruse 	else
1071*e8227804SMichael Kruse 		osprintf(os, "    : ptr(nullptr) {}\n\n");
1072*e8227804SMichael Kruse 	osprintf(os, "%s::%s(const %s &obj)\n", cppname, cppname, cppname);
1073*e8227804SMichael Kruse 	if (subclass)
1074*e8227804SMichael Kruse 		osprintf(os, "    : %s(obj)\n", super.c_str());
1075*e8227804SMichael Kruse 	else
1076*e8227804SMichael Kruse 		osprintf(os, "    : ptr(nullptr)\n");
1077d169d70bSTobias Grosser 	osprintf(os, "{\n");
1078*e8227804SMichael Kruse 	if (!subclass) {
107926269d34STobias Grosser 		print_check_ptr_start(os, clazz, "obj.ptr");
1080d169d70bSTobias Grosser 		osprintf(os, "  ptr = obj.copy();\n");
1081*e8227804SMichael Kruse 		if (clazz.has_persistent_callbacks())
1082*e8227804SMichael Kruse 			osprintf(os, "  copy_callbacks(obj);\n");
108326269d34STobias Grosser 		print_check_ptr_end(os, "ptr");
1084*e8227804SMichael Kruse 	}
1085*e8227804SMichael Kruse 	osprintf(os, "}\n");
1086*e8227804SMichael Kruse }
1087*e8227804SMichael Kruse 
1088*e8227804SMichael Kruse /* Print definition for "method" in class "clazz" to "os",
1089*e8227804SMichael Kruse  * without any automatic type conversions.
1090*e8227804SMichael Kruse  *
1091*e8227804SMichael Kruse  * "kind" specifies the kind of method that should be generated.
1092*e8227804SMichael Kruse  *
1093*e8227804SMichael Kruse  * This method distinguishes three kinds of methods: member methods, static
1094*e8227804SMichael Kruse  * methods, and constructors.
1095*e8227804SMichael Kruse  *
1096*e8227804SMichael Kruse  * Member methods call "method" by passing to the underlying isl function the
1097*e8227804SMichael Kruse  * isl object belonging to "this" as first argument and the remaining arguments
1098*e8227804SMichael Kruse  * as subsequent arguments.
1099*e8227804SMichael Kruse  *
1100*e8227804SMichael Kruse  * Static methods call "method" by passing all arguments to the underlying isl
1101*e8227804SMichael Kruse  * function, as no this-pointer is available. The result is a newly managed
1102*e8227804SMichael Kruse  * isl C++ object.
1103*e8227804SMichael Kruse  *
1104*e8227804SMichael Kruse  * Constructors create a new object from a given set of input parameters. They
1105*e8227804SMichael Kruse  * do not return a value, but instead update the pointer stored inside the
1106*e8227804SMichael Kruse  * newly created object.
1107*e8227804SMichael Kruse  *
1108*e8227804SMichael Kruse  * If the method has a callback argument, we reduce the number of parameters
1109*e8227804SMichael Kruse  * that are exposed by one to hide the user pointer from the interface. On
1110*e8227804SMichael Kruse  * the C++ side no user pointer is needed, as arguments can be forwarded
1111*e8227804SMichael Kruse  * as part of the std::function argument which specifies the callback function.
1112*e8227804SMichael Kruse  *
1113*e8227804SMichael Kruse  * Unless checked C++ bindings are being generated,
1114*e8227804SMichael Kruse  * the inputs of the method are first checked for being valid isl objects and
1115*e8227804SMichael Kruse  * a copy of the associated isl::ctx is saved (if needed).
1116*e8227804SMichael Kruse  * If any failure occurs, either during the check for the inputs or
1117*e8227804SMichael Kruse  * during the isl function call, an exception is thrown.
1118*e8227804SMichael Kruse  * During the function call, isl is made not to print any error message
1119*e8227804SMichael Kruse  * because the error message is included in the exception.
1120*e8227804SMichael Kruse  */
1121*e8227804SMichael Kruse template<>
1122*e8227804SMichael Kruse void cpp_generator::print_method<cpp_generator::impl>(ostream &os,
1123*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *method, function_kind kind)
1124*e8227804SMichael Kruse {
1125*e8227804SMichael Kruse 	string methodname = method->getName();
1126*e8227804SMichael Kruse 	int num_params = method->getNumParams();
1127*e8227804SMichael Kruse 
1128*e8227804SMichael Kruse 	osprintf(os, "\n");
1129*e8227804SMichael Kruse 	print_method_header(os, clazz, method, false, kind);
1130*e8227804SMichael Kruse 	osprintf(os, "{\n");
1131*e8227804SMichael Kruse 	print_argument_validity_check(os, method, kind);
1132*e8227804SMichael Kruse 	print_save_ctx(os, method, kind);
1133*e8227804SMichael Kruse 	print_on_error_continue(os);
1134*e8227804SMichael Kruse 
1135*e8227804SMichael Kruse 	for (int i = 0; i < num_params; ++i) {
1136*e8227804SMichael Kruse 		ParmVarDecl *param = method->getParamDecl(i);
1137*e8227804SMichael Kruse 		if (is_callback(param->getType())) {
1138*e8227804SMichael Kruse 			num_params -= 1;
1139*e8227804SMichael Kruse 			print_callback_local(os, param);
1140*e8227804SMichael Kruse 		}
1141*e8227804SMichael Kruse 	}
1142*e8227804SMichael Kruse 
1143*e8227804SMichael Kruse 	osprintf(os, "  auto res = %s(", methodname.c_str());
1144*e8227804SMichael Kruse 
1145*e8227804SMichael Kruse 	for (int i = 0; i < num_params; ++i) {
1146*e8227804SMichael Kruse 		ParmVarDecl *param = method->getParamDecl(i);
1147*e8227804SMichael Kruse 		bool load_from_this_ptr = false;
1148*e8227804SMichael Kruse 
1149*e8227804SMichael Kruse 		if (i == 0 && kind == function_kind_member_method)
1150*e8227804SMichael Kruse 			load_from_this_ptr = true;
1151*e8227804SMichael Kruse 
1152*e8227804SMichael Kruse 		print_method_param_use(os, param, load_from_this_ptr);
1153*e8227804SMichael Kruse 
1154*e8227804SMichael Kruse 		if (i != num_params - 1)
1155*e8227804SMichael Kruse 			osprintf(os, ", ");
1156*e8227804SMichael Kruse 	}
1157*e8227804SMichael Kruse 	osprintf(os, ");\n");
1158*e8227804SMichael Kruse 
1159*e8227804SMichael Kruse 	print_exceptional_execution_check(os, clazz, method, kind);
1160*e8227804SMichael Kruse 	if (kind == function_kind_constructor) {
1161*e8227804SMichael Kruse 		osprintf(os, "  ptr = res;\n");
1162*e8227804SMichael Kruse 	} else {
1163*e8227804SMichael Kruse 		print_method_return(os, clazz, method);
1164*e8227804SMichael Kruse 	}
1165*e8227804SMichael Kruse 
1166*e8227804SMichael Kruse 	osprintf(os, "}\n");
1167*e8227804SMichael Kruse }
1168*e8227804SMichael Kruse 
1169*e8227804SMichael Kruse /* Print a definition for "method" in class "clazz" to "os",
1170*e8227804SMichael Kruse  * where at least one of the argument types needs to be converted,
1171*e8227804SMichael Kruse  * as specified by "convert".
1172*e8227804SMichael Kruse  *
1173*e8227804SMichael Kruse  * "kind" specifies the kind of method that should be generated and
1174*e8227804SMichael Kruse  * is assumed to be set to function_kind_member_method.
1175*e8227804SMichael Kruse  *
1176*e8227804SMichael Kruse  * The generated method performs the required conversion(s) and
1177*e8227804SMichael Kruse  * calls the method generated without conversions.
1178*e8227804SMichael Kruse  *
1179*e8227804SMichael Kruse  * Each conversion is performed by calling the conversion function
1180*e8227804SMichael Kruse  * with as arguments the isl_ctx of the object and the argument
1181*e8227804SMichael Kruse  * to the generated method.
1182*e8227804SMichael Kruse  * In order to be able to use this isl_ctx, the current object needs
1183*e8227804SMichael Kruse  * to valid.  The validity of other arguments is checked
1184*e8227804SMichael Kruse  * by the called method.
1185*e8227804SMichael Kruse  */
1186*e8227804SMichael Kruse template<>
1187*e8227804SMichael Kruse void cpp_generator::print_method<cpp_generator::impl>(ostream &os,
1188*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *method, function_kind kind,
1189*e8227804SMichael Kruse 	const std::vector<bool> &convert)
1190*e8227804SMichael Kruse {
1191*e8227804SMichael Kruse 	string name = clazz.method_name(method);
1192*e8227804SMichael Kruse 	int num_params = method->getNumParams();
1193*e8227804SMichael Kruse 
1194*e8227804SMichael Kruse 	if (kind != function_kind_member_method)
1195*e8227804SMichael Kruse 		die("Automatic conversion currently only supported "
1196*e8227804SMichael Kruse 		    "for object methods");
1197*e8227804SMichael Kruse 
1198*e8227804SMichael Kruse 	osprintf(os, "\n");
1199*e8227804SMichael Kruse 	print_named_method_header(os, clazz, method, name, false,
1200*e8227804SMichael Kruse 				  kind, convert);
1201*e8227804SMichael Kruse 	osprintf(os, "{\n");
1202*e8227804SMichael Kruse 	print_check_ptr(os, "ptr");
1203*e8227804SMichael Kruse 	osprintf(os, "  return this->%s(", name.c_str());
1204*e8227804SMichael Kruse 	for (int i = 1; i < num_params; ++i) {
1205*e8227804SMichael Kruse 		ParmVarDecl *param = method->getParamDecl(i);
1206*e8227804SMichael Kruse 		std::string name = param->getName().str();
1207*e8227804SMichael Kruse 
1208*e8227804SMichael Kruse 		if (i != 1)
1209*e8227804SMichael Kruse 			osprintf(os, ", ");
1210*e8227804SMichael Kruse 		if (convert[i]) {
1211*e8227804SMichael Kruse 			QualType type = param->getOriginalType();
1212*e8227804SMichael Kruse 			string cpptype = type2cpp(type);
1213*e8227804SMichael Kruse 			osprintf(os, "%s(ctx(), %s)",
1214*e8227804SMichael Kruse 				cpptype.c_str(), name.c_str());
1215*e8227804SMichael Kruse 		} else {
1216*e8227804SMichael Kruse 			osprintf(os, "%s", name.c_str());
1217*e8227804SMichael Kruse 		}
1218*e8227804SMichael Kruse 	}
1219*e8227804SMichael Kruse 	osprintf(os, ");\n");
1220d169d70bSTobias Grosser 	osprintf(os, "}\n");
1221d169d70bSTobias Grosser }
1222d169d70bSTobias Grosser 
1223d169d70bSTobias Grosser /* Print implementations of constructors for class "clazz" to "os".
1224d169d70bSTobias Grosser  */
1225d169d70bSTobias Grosser void cpp_generator::print_constructors_impl(ostream &os,
1226d169d70bSTobias Grosser        const isl_class &clazz)
1227d169d70bSTobias Grosser {
1228*e8227804SMichael Kruse 	function_set::const_iterator in;
1229*e8227804SMichael Kruse 	const function_set constructors = clazz.constructors;
1230d169d70bSTobias Grosser 
1231d169d70bSTobias Grosser 	for (in = constructors.begin(); in != constructors.end(); ++in) {
1232d169d70bSTobias Grosser 		FunctionDecl *cons = *in;
1233d169d70bSTobias Grosser 
1234*e8227804SMichael Kruse 		print_method<impl>(os, clazz, cons, function_kind_constructor);
1235d169d70bSTobias Grosser 	}
1236d169d70bSTobias Grosser }
1237d169d70bSTobias Grosser 
1238d169d70bSTobias Grosser /* Print implementation of copy assignment operator for class "clazz" to "os".
1239*e8227804SMichael Kruse  *
1240*e8227804SMichael Kruse  * If the class has any persistent callbacks, then copy them
1241*e8227804SMichael Kruse  * from the original object.
1242d169d70bSTobias Grosser  */
1243d169d70bSTobias Grosser void cpp_generator::print_copy_assignment_impl(ostream &os,
1244d169d70bSTobias Grosser 	const isl_class &clazz)
1245d169d70bSTobias Grosser {
1246d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
1247d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
1248d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
1249d169d70bSTobias Grosser 
1250*e8227804SMichael Kruse 	osprintf(os, "\n");
1251d169d70bSTobias Grosser 	osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname,
1252d169d70bSTobias Grosser 		 cppname, cppname);
1253d169d70bSTobias Grosser 	osprintf(os, "  std::swap(this->ptr, obj.ptr);\n", name);
1254*e8227804SMichael Kruse 	if (clazz.has_persistent_callbacks())
1255*e8227804SMichael Kruse 		osprintf(os, "  copy_callbacks(obj);\n");
1256d169d70bSTobias Grosser 	osprintf(os, "  return *this;\n");
1257d169d70bSTobias Grosser 	osprintf(os, "}\n");
1258d169d70bSTobias Grosser }
1259d169d70bSTobias Grosser 
1260d169d70bSTobias Grosser /* Print implementation of destructor for class "clazz" to "os".
1261*e8227804SMichael Kruse  *
1262*e8227804SMichael Kruse  * No explicit destructor is needed for type based subclasses.
1263d169d70bSTobias Grosser  */
1264d169d70bSTobias Grosser void cpp_generator::print_destructor_impl(ostream &os,
1265d169d70bSTobias Grosser 	const isl_class &clazz)
1266d169d70bSTobias Grosser {
1267d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
1268d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
1269d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
1270d169d70bSTobias Grosser 
1271*e8227804SMichael Kruse 	if (clazz.is_type_subclass())
1272*e8227804SMichael Kruse 		return;
1273*e8227804SMichael Kruse 
1274*e8227804SMichael Kruse 	osprintf(os, "\n");
1275d169d70bSTobias Grosser 	osprintf(os, "%s::~%s() {\n", cppname, cppname);
1276d169d70bSTobias Grosser 	osprintf(os, "  if (ptr)\n");
1277d169d70bSTobias Grosser 	osprintf(os, "    %s_free(ptr);\n", name);
1278d169d70bSTobias Grosser 	osprintf(os, "}\n");
1279d169d70bSTobias Grosser }
1280d169d70bSTobias Grosser 
1281*e8227804SMichael Kruse /* Print a check that the persistent callback corresponding to "fd"
1282*e8227804SMichael Kruse  * is not set, throwing an exception (or printing an error message
1283*e8227804SMichael Kruse  * and returning nullptr) if it is set.
1284*e8227804SMichael Kruse  */
1285*e8227804SMichael Kruse void cpp_generator::print_check_no_persistent_callback(ostream &os,
1286*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *fd)
1287*e8227804SMichael Kruse {
1288*e8227804SMichael Kruse 	string callback_name = clazz.persistent_callback_name(fd);
1289*e8227804SMichael Kruse 
1290*e8227804SMichael Kruse 	osprintf(os, "  if (%s_data)\n", callback_name.c_str());
1291*e8227804SMichael Kruse 	print_invalid(os, 4, "cannot release object with persistent callbacks",
1292*e8227804SMichael Kruse 			    "return nullptr");
1293*e8227804SMichael Kruse }
1294*e8227804SMichael Kruse 
1295d169d70bSTobias Grosser /* Print implementation of ptr() functions for class "clazz" to "os".
1296*e8227804SMichael Kruse  * Since type based subclasses share the pointer with their superclass,
1297*e8227804SMichael Kruse  * they can also reuse these functions from the superclass.
1298*e8227804SMichael Kruse  *
1299*e8227804SMichael Kruse  * If an object has persistent callbacks set, then the underlying
1300*e8227804SMichael Kruse  * C object pointer cannot be released because it references data
1301*e8227804SMichael Kruse  * in the C++ object.
1302d169d70bSTobias Grosser  */
1303d169d70bSTobias Grosser void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
1304d169d70bSTobias Grosser {
1305d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
1306d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
1307d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
1308*e8227804SMichael Kruse 	set<FunctionDecl *>::const_iterator in;
1309*e8227804SMichael Kruse 	const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
1310d169d70bSTobias Grosser 
1311*e8227804SMichael Kruse 	if (clazz.is_type_subclass())
1312*e8227804SMichael Kruse 		return;
1313*e8227804SMichael Kruse 
1314*e8227804SMichael Kruse 	osprintf(os, "\n");
1315d169d70bSTobias Grosser 	osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
1316d169d70bSTobias Grosser 	osprintf(os, "  return %s_copy(ptr);\n", name);
1317d169d70bSTobias Grosser 	osprintf(os, "}\n\n");
1318d169d70bSTobias Grosser 	osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
1319d169d70bSTobias Grosser 	osprintf(os, "  return ptr;\n");
1320d169d70bSTobias Grosser 	osprintf(os, "}\n\n");
1321d169d70bSTobias Grosser 	osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
1322*e8227804SMichael Kruse 	for (in = callbacks.begin(); in != callbacks.end(); ++in)
1323*e8227804SMichael Kruse 		print_check_no_persistent_callback(os, clazz, *in);
1324d169d70bSTobias Grosser 	osprintf(os, "  %s *tmp = ptr;\n", name);
1325d169d70bSTobias Grosser 	osprintf(os, "  ptr = nullptr;\n");
1326d169d70bSTobias Grosser 	osprintf(os, "  return tmp;\n");
1327d169d70bSTobias Grosser 	osprintf(os, "}\n\n");
1328d169d70bSTobias Grosser 	osprintf(os, "bool %s::is_null() const {\n", cppname);
1329d169d70bSTobias Grosser 	osprintf(os, "  return ptr == nullptr;\n");
1330d169d70bSTobias Grosser 	osprintf(os, "}\n");
1331d169d70bSTobias Grosser }
1332d169d70bSTobias Grosser 
1333*e8227804SMichael Kruse /* Print implementations for the "as" and "isa" methods, if "clazz"
1334*e8227804SMichael Kruse  * is a superclass with a type function.
1335*e8227804SMichael Kruse  *
1336*e8227804SMichael Kruse  * "isa" checks whether an object is of a given subclass type.
1337*e8227804SMichael Kruse  * "isa_type" does the same, but gets passed the value of the type field
1338*e8227804SMichael Kruse  * of the subclass as a function argument and the type of this field
1339*e8227804SMichael Kruse  * as a template argument.
1340*e8227804SMichael Kruse  * "as" casts an object to a given subclass type, erroring out
1341*e8227804SMichael Kruse  * if the object is not of the given type.
1342*e8227804SMichael Kruse  *
1343*e8227804SMichael Kruse  * If the input is an invalid object, then these methods raise
1344*e8227804SMichael Kruse  * an exception.
1345*e8227804SMichael Kruse  * If checked bindings are being generated,
1346*e8227804SMichael Kruse  * then an invalid boolean or object is returned instead.
1347d169d70bSTobias Grosser  */
1348*e8227804SMichael Kruse void cpp_generator::print_downcast_impl(ostream &os, const isl_class &clazz)
1349*e8227804SMichael Kruse {
1350*e8227804SMichael Kruse 	std::string cppstring = type2cpp(clazz);
1351*e8227804SMichael Kruse 	const char *cppname = cppstring.c_str();
1352*e8227804SMichael Kruse 
1353*e8227804SMichael Kruse 	if (!clazz.fn_type)
1354*e8227804SMichael Kruse 		return;
1355*e8227804SMichael Kruse 
1356*e8227804SMichael Kruse 	osprintf(os, "\n");
1357*e8227804SMichael Kruse 	osprintf(os, "template <typename T, typename>\n");
1358*e8227804SMichael Kruse 	osprintf(os, "%s %s::isa_type(T subtype) const\n",
1359*e8227804SMichael Kruse 		isl_bool2cpp().c_str(), cppname);
1360*e8227804SMichael Kruse 	osprintf(os, "{\n");
1361*e8227804SMichael Kruse 	osprintf(os, "  if (is_null())\n");
1362*e8227804SMichael Kruse 	if (checked)
1363*e8227804SMichael Kruse 		osprintf(os, "    return boolean();\n");
1364*e8227804SMichael Kruse 	else
1365*e8227804SMichael Kruse 		print_throw_NULL_input(os);
1366*e8227804SMichael Kruse 	osprintf(os, "  return %s(get()) == subtype;\n",
1367*e8227804SMichael Kruse 		clazz.fn_type->getNameAsString().c_str());
1368*e8227804SMichael Kruse 	osprintf(os, "}\n");
1369*e8227804SMichael Kruse 
1370*e8227804SMichael Kruse 	osprintf(os, "template <class T>\n");
1371*e8227804SMichael Kruse 	osprintf(os, "%s %s::isa() const\n", isl_bool2cpp().c_str(), cppname);
1372*e8227804SMichael Kruse 	osprintf(os, "{\n");
1373*e8227804SMichael Kruse 	osprintf(os, "  return isa_type<decltype(T::type)>(T::type);\n");
1374*e8227804SMichael Kruse 	osprintf(os, "}\n");
1375*e8227804SMichael Kruse 
1376*e8227804SMichael Kruse 	osprintf(os, "template <class T>\n");
1377*e8227804SMichael Kruse 	osprintf(os, "T %s::as() const\n", cppname);
1378*e8227804SMichael Kruse 	osprintf(os, "{\n");
1379*e8227804SMichael Kruse 	if (checked)
1380*e8227804SMichael Kruse 		osprintf(os, " if (isa<T>().is_false())\n");
1381*e8227804SMichael Kruse 	else
1382*e8227804SMichael Kruse 		osprintf(os, " if (!isa<T>())\n");
1383*e8227804SMichael Kruse 	print_invalid(os, 4, "not an object of the requested subtype",
1384*e8227804SMichael Kruse 		    "return T()");
1385*e8227804SMichael Kruse 	osprintf(os, "  return T(copy());\n");
1386*e8227804SMichael Kruse 	osprintf(os, "}\n");
1387*e8227804SMichael Kruse }
1388*e8227804SMichael Kruse 
1389*e8227804SMichael Kruse /* Print the implementation of the ctx method.
1390*e8227804SMichael Kruse  */
1391*e8227804SMichael Kruse void cpp_generator::print_ctx_impl(ostream &os, const isl_class &clazz)
1392d169d70bSTobias Grosser {
1393d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
1394d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
1395d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
1396*e8227804SMichael Kruse 	std::string ns = isl_namespace();
1397d169d70bSTobias Grosser 
1398*e8227804SMichael Kruse 	osprintf(os, "\n");
1399*e8227804SMichael Kruse 	osprintf(os, "%sctx %s::ctx() const {\n", ns.c_str(), cppname);
1400*e8227804SMichael Kruse 	osprintf(os, "  return %sctx(%s_get_ctx(ptr));\n", ns.c_str(), name);
1401d169d70bSTobias Grosser 	osprintf(os, "}\n");
1402d169d70bSTobias Grosser }
1403d169d70bSTobias Grosser 
1404*e8227804SMichael Kruse /* Print the implementations of the methods needed for the persistent callbacks
1405*e8227804SMichael Kruse  * of "clazz".
1406*e8227804SMichael Kruse  */
1407*e8227804SMichael Kruse void cpp_generator::print_persistent_callbacks_impl(ostream &os,
1408*e8227804SMichael Kruse        const isl_class &clazz)
1409*e8227804SMichael Kruse {
1410*e8227804SMichael Kruse 	std::string cppstring = type2cpp(clazz);
1411*e8227804SMichael Kruse 	const char *cppname = cppstring.c_str();
1412*e8227804SMichael Kruse 	string classname = type2cpp(clazz);
1413*e8227804SMichael Kruse 	set<FunctionDecl *>::const_iterator in;
1414*e8227804SMichael Kruse 	const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
1415*e8227804SMichael Kruse 
1416*e8227804SMichael Kruse 	if (!clazz.has_persistent_callbacks())
1417*e8227804SMichael Kruse 		return;
1418*e8227804SMichael Kruse 
1419*e8227804SMichael Kruse 	osprintf(os, "\n");
1420*e8227804SMichael Kruse 	osprintf(os, "%s &%s::copy_callbacks(const %s &obj)\n",
1421*e8227804SMichael Kruse 		cppname, classname.c_str(), cppname);
1422*e8227804SMichael Kruse 	osprintf(os, "{\n");
1423*e8227804SMichael Kruse 	for (in = callbacks.begin(); in != callbacks.end(); ++in) {
1424*e8227804SMichael Kruse 		string callback_name = clazz.persistent_callback_name(*in);
1425*e8227804SMichael Kruse 
1426*e8227804SMichael Kruse 		osprintf(os, "  %s_data = obj.%s_data;\n",
1427*e8227804SMichael Kruse 			callback_name.c_str(), callback_name.c_str());
1428*e8227804SMichael Kruse 	}
1429*e8227804SMichael Kruse 	osprintf(os, "  return *this;\n");
1430*e8227804SMichael Kruse 	osprintf(os, "}\n");
1431*e8227804SMichael Kruse 
1432*e8227804SMichael Kruse 	for (in = callbacks.begin(); in != callbacks.end(); ++in) {
1433*e8227804SMichael Kruse 		function_kind kind = function_kind_member_method;
1434*e8227804SMichael Kruse 
1435*e8227804SMichael Kruse 		print_set_persistent_callback(os, clazz, *in, kind);
1436*e8227804SMichael Kruse 	}
1437*e8227804SMichael Kruse }
1438*e8227804SMichael Kruse 
1439d169d70bSTobias Grosser /* Print definitions for methods of class "clazz" to "os".
1440d169d70bSTobias Grosser  */
1441d169d70bSTobias Grosser void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz)
1442d169d70bSTobias Grosser {
1443*e8227804SMichael Kruse 	map<string, function_set>::const_iterator it;
1444d169d70bSTobias Grosser 
1445*e8227804SMichael Kruse 	for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
14466145b11cSTobias Grosser 		print_method_group_impl(os, clazz, it->second);
1447d169d70bSTobias Grosser }
1448*e8227804SMichael Kruse 
1449*e8227804SMichael Kruse /* Print the definition for a method "method_name" in "clazz" derived
1450*e8227804SMichael Kruse  * from "fd", which sets an enum, to "os".
1451*e8227804SMichael Kruse  * In particular, the method "method_name" sets the enum to "enum_name".
1452*e8227804SMichael Kruse  *
1453*e8227804SMichael Kruse  * The last argument of the C function does not appear in the method call,
1454*e8227804SMichael Kruse  * but is fixed to "enum_name" instead.
1455*e8227804SMichael Kruse  * Other than that, the method printed here is similar to one
1456*e8227804SMichael Kruse  * printed by cpp_generator::print_method_impl, except that
1457*e8227804SMichael Kruse  * some of the special cases do not occur.
1458*e8227804SMichael Kruse  */
1459*e8227804SMichael Kruse void cpp_generator::print_set_enum_impl(ostream &os, const isl_class &clazz,
1460*e8227804SMichael Kruse 	FunctionDecl *fd, const string &enum_name, const string &method_name)
1461*e8227804SMichael Kruse {
1462*e8227804SMichael Kruse 	string c_name = fd->getName();
1463*e8227804SMichael Kruse 	int n = fd->getNumParams();
1464*e8227804SMichael Kruse 	function_kind kind = function_kind_member_method;
1465*e8227804SMichael Kruse 
1466*e8227804SMichael Kruse 	osprintf(os, "\n");
1467*e8227804SMichael Kruse 	print_method_header(os, clazz, fd, method_name, n - 1, false, kind);
1468*e8227804SMichael Kruse 	osprintf(os, "{\n");
1469*e8227804SMichael Kruse 
1470*e8227804SMichael Kruse 	print_argument_validity_check(os, fd, kind);
1471*e8227804SMichael Kruse 	print_save_ctx(os, fd, kind);
1472*e8227804SMichael Kruse 	print_on_error_continue(os);
1473*e8227804SMichael Kruse 
1474*e8227804SMichael Kruse 	osprintf(os, "  auto res = %s(", c_name.c_str());
1475*e8227804SMichael Kruse 
1476*e8227804SMichael Kruse 	for (int i = 0; i < n - 1; ++i) {
1477*e8227804SMichael Kruse 		ParmVarDecl *param = fd->getParamDecl(i);
1478*e8227804SMichael Kruse 
1479*e8227804SMichael Kruse 		if (i > 0)
1480*e8227804SMichael Kruse 			osprintf(os, ", ");
1481*e8227804SMichael Kruse 		print_method_param_use(os, param, i == 0);
1482*e8227804SMichael Kruse 	}
1483*e8227804SMichael Kruse 	osprintf(os, ", %s", enum_name.c_str());
1484*e8227804SMichael Kruse 	osprintf(os, ");\n");
1485*e8227804SMichael Kruse 
1486*e8227804SMichael Kruse 	print_exceptional_execution_check(os, clazz, fd, kind);
1487*e8227804SMichael Kruse 	print_method_return(os, clazz, fd);
1488*e8227804SMichael Kruse 
1489*e8227804SMichael Kruse 	osprintf(os, "}\n");
1490*e8227804SMichael Kruse }
1491*e8227804SMichael Kruse 
1492*e8227804SMichael Kruse /* Print definitions for the methods in "clazz" derived from "fd",
1493*e8227804SMichael Kruse  * which sets an enum, to "os".
1494*e8227804SMichael Kruse  *
1495*e8227804SMichael Kruse  * A method is generated for each value in the enum, setting
1496*e8227804SMichael Kruse  * the enum to that value.
1497*e8227804SMichael Kruse  */
1498*e8227804SMichael Kruse void cpp_generator::print_set_enums_impl(ostream &os, const isl_class &clazz,
1499*e8227804SMichael Kruse 	FunctionDecl *fd)
1500*e8227804SMichael Kruse {
1501*e8227804SMichael Kruse 	vector<set_enum>::const_iterator it;
1502*e8227804SMichael Kruse 	const vector<set_enum> &set_enums = clazz.set_enums.at(fd);
1503*e8227804SMichael Kruse 
1504*e8227804SMichael Kruse 	for (it = set_enums.begin(); it != set_enums.end(); ++it) {
1505*e8227804SMichael Kruse 		osprintf(os, "\n");
1506*e8227804SMichael Kruse 		print_set_enum_impl(os, clazz, fd, it->name, it->method_name);
1507*e8227804SMichael Kruse 	}
1508*e8227804SMichael Kruse }
1509*e8227804SMichael Kruse 
1510*e8227804SMichael Kruse /* Print definitions for methods in "clazz" derived from functions
1511*e8227804SMichael Kruse  * that set an enum, to "os".
1512*e8227804SMichael Kruse  */
1513*e8227804SMichael Kruse void cpp_generator::print_set_enums_impl(ostream &os, const isl_class &clazz)
1514*e8227804SMichael Kruse {
1515*e8227804SMichael Kruse 	map<FunctionDecl *, vector<set_enum> >::const_iterator it;
1516*e8227804SMichael Kruse 
1517*e8227804SMichael Kruse 	for (it = clazz.set_enums.begin(); it != clazz.set_enums.end(); ++it)
1518*e8227804SMichael Kruse 		print_set_enums_impl(os, clazz, it->first);
1519*e8227804SMichael Kruse }
1520*e8227804SMichael Kruse 
1521*e8227804SMichael Kruse /* Print a definition for the "get" method "fd" in class "clazz",
1522*e8227804SMichael Kruse  * using a name that includes the "get_" prefix, to "os".
1523*e8227804SMichael Kruse  *
1524*e8227804SMichael Kruse  * This definition simply calls the variant without the "get_" prefix and
1525*e8227804SMichael Kruse  * returns its result.
1526*e8227804SMichael Kruse  * Note that static methods are not considered to be "get" methods.
1527*e8227804SMichael Kruse  */
1528*e8227804SMichael Kruse template<>
1529*e8227804SMichael Kruse void cpp_generator::print_get_method<cpp_generator::impl>(ostream &os,
1530*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *fd)
1531*e8227804SMichael Kruse {
1532*e8227804SMichael Kruse 	string get_name = clazz.base_method_name(fd);
1533*e8227804SMichael Kruse 	string name = clazz.method_name(fd);
1534*e8227804SMichael Kruse 	function_kind kind = function_kind_member_method;
1535*e8227804SMichael Kruse 	int num_params = fd->getNumParams();
1536*e8227804SMichael Kruse 
1537*e8227804SMichael Kruse 	osprintf(os, "\n");
1538*e8227804SMichael Kruse 	print_named_method_header(os, clazz, fd, get_name, false, kind);
1539*e8227804SMichael Kruse 	osprintf(os, "{\n");
1540*e8227804SMichael Kruse 	osprintf(os, "  return %s(", name.c_str());
1541*e8227804SMichael Kruse 	for (int i = 1; i < num_params; ++i) {
1542*e8227804SMichael Kruse 		ParmVarDecl *param = fd->getParamDecl(i);
1543*e8227804SMichael Kruse 
1544*e8227804SMichael Kruse 		if (i != 1)
1545*e8227804SMichael Kruse 			osprintf(os, ", ");
1546*e8227804SMichael Kruse 		osprintf(os, "%s", param->getName().str().c_str());
1547*e8227804SMichael Kruse 	}
1548*e8227804SMichael Kruse 	osprintf(os, ");\n");
1549*e8227804SMichael Kruse 	osprintf(os, "}\n");
1550d169d70bSTobias Grosser }
1551d169d70bSTobias Grosser 
15526145b11cSTobias Grosser /* Print definitions for methods "methods" in class "clazz" to "os".
1553d169d70bSTobias Grosser  */
1554d169d70bSTobias Grosser void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz,
1555*e8227804SMichael Kruse 	const function_set &methods)
1556d169d70bSTobias Grosser {
1557*e8227804SMichael Kruse 	function_set::const_iterator it;
1558d169d70bSTobias Grosser 
1559*e8227804SMichael Kruse 	for (it = methods.begin(); it != methods.end(); ++it)
1560*e8227804SMichael Kruse 		print_method_variants<impl>(os, clazz, *it);
1561d169d70bSTobias Grosser }
1562d169d70bSTobias Grosser 
1563d169d70bSTobias Grosser /* Print the use of "param" to "os".
1564d169d70bSTobias Grosser  *
1565d169d70bSTobias Grosser  * "load_from_this_ptr" specifies whether the parameter should be loaded from
1566d169d70bSTobias Grosser  * the this-ptr.  In case a value is loaded from a this pointer, the original
1567d169d70bSTobias Grosser  * value must be preserved and must consequently be copied.  Values that are
1568d169d70bSTobias Grosser  * loaded from parameters do not need to be preserved, as such values will
1569d169d70bSTobias Grosser  * already be copies of the actual parameters.  It is consequently possible
1570d169d70bSTobias Grosser  * to directly take the pointer from these values, which saves
1571d169d70bSTobias Grosser  * an unnecessary copy.
1572d169d70bSTobias Grosser  *
1573d169d70bSTobias Grosser  * In case the parameter is a callback function, two parameters get printed,
1574d169d70bSTobias Grosser  * a wrapper for the callback function and a pointer to the actual
1575d169d70bSTobias Grosser  * callback function.  The wrapper is expected to be available
1576d169d70bSTobias Grosser  * in a previously declared variable <name>_lambda, while
1577d169d70bSTobias Grosser  * the actual callback function is expected to be stored
1578d169d70bSTobias Grosser  * in a structure called <name>_data.
1579d169d70bSTobias Grosser  * The caller of this function must ensure that these variables exist.
1580d169d70bSTobias Grosser  */
1581d169d70bSTobias Grosser void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param,
1582d169d70bSTobias Grosser 	bool load_from_this_ptr)
1583d169d70bSTobias Grosser {
1584d169d70bSTobias Grosser 	string name = param->getName().str();
1585d169d70bSTobias Grosser 	const char *name_str = name.c_str();
1586d169d70bSTobias Grosser 	QualType type = param->getOriginalType();
1587d169d70bSTobias Grosser 
1588d169d70bSTobias Grosser 	if (type->isIntegerType()) {
1589d169d70bSTobias Grosser 		osprintf(os, "%s", name_str);
1590d169d70bSTobias Grosser 		return;
1591d169d70bSTobias Grosser 	}
1592d169d70bSTobias Grosser 
1593d169d70bSTobias Grosser 	if (is_string(type)) {
1594d169d70bSTobias Grosser 		osprintf(os, "%s.c_str()", name_str);
1595d169d70bSTobias Grosser 		return;
1596d169d70bSTobias Grosser 	}
1597d169d70bSTobias Grosser 
1598d169d70bSTobias Grosser 	if (is_callback(type)) {
1599d169d70bSTobias Grosser 		osprintf(os, "%s_lambda, ", name_str);
1600d169d70bSTobias Grosser 		osprintf(os, "&%s_data", name_str);
1601d169d70bSTobias Grosser 		return;
1602d169d70bSTobias Grosser 	}
1603d169d70bSTobias Grosser 
1604*e8227804SMichael Kruse 	if (!load_from_this_ptr)
1605d169d70bSTobias Grosser 		osprintf(os, "%s.", name_str);
1606d169d70bSTobias Grosser 
1607d169d70bSTobias Grosser 	if (keeps(param)) {
1608d169d70bSTobias Grosser 		osprintf(os, "get()");
1609d169d70bSTobias Grosser 	} else {
1610d169d70bSTobias Grosser 		if (load_from_this_ptr)
1611d169d70bSTobias Grosser 			osprintf(os, "copy()");
1612d169d70bSTobias Grosser 		else
1613d169d70bSTobias Grosser 			osprintf(os, "release()");
1614d169d70bSTobias Grosser 	}
1615d169d70bSTobias Grosser }
1616d169d70bSTobias Grosser 
1617d169d70bSTobias Grosser /* Print code that checks that all isl object arguments to "method" are valid
1618d169d70bSTobias Grosser  * (not NULL) and throws an exception if they are not.
1619d169d70bSTobias Grosser  * "kind" specifies the kind of method that is being generated.
1620d169d70bSTobias Grosser  *
1621d169d70bSTobias Grosser  * If checked bindings are being generated,
1622d169d70bSTobias Grosser  * then no such check is performed.
1623d169d70bSTobias Grosser  */
1624d169d70bSTobias Grosser void cpp_generator::print_argument_validity_check(ostream &os,
1625d169d70bSTobias Grosser 	FunctionDecl *method, function_kind kind)
1626d169d70bSTobias Grosser {
1627d169d70bSTobias Grosser 	int n;
1628d169d70bSTobias Grosser 	bool first = true;
1629d169d70bSTobias Grosser 
1630d169d70bSTobias Grosser 	if (checked)
1631d169d70bSTobias Grosser 		return;
1632d169d70bSTobias Grosser 
1633d169d70bSTobias Grosser 	n = method->getNumParams();
1634d169d70bSTobias Grosser 	for (int i = 0; i < n; ++i) {
1635d169d70bSTobias Grosser 		bool is_this;
1636d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
1637d169d70bSTobias Grosser 		string name = param->getName().str();
1638d169d70bSTobias Grosser 		const char *name_str = name.c_str();
1639d169d70bSTobias Grosser 		QualType type = param->getOriginalType();
1640d169d70bSTobias Grosser 
1641d169d70bSTobias Grosser 		is_this = i == 0 && kind == function_kind_member_method;
1642d169d70bSTobias Grosser 		if (!is_this && (is_isl_ctx(type) || !is_isl_type(type)))
1643d169d70bSTobias Grosser 			continue;
1644d169d70bSTobias Grosser 
1645d169d70bSTobias Grosser 		if (first)
1646d169d70bSTobias Grosser 			osprintf(os, "  if (");
1647d169d70bSTobias Grosser 		else
1648d169d70bSTobias Grosser 			osprintf(os, " || ");
1649d169d70bSTobias Grosser 
1650d169d70bSTobias Grosser 		if (is_this)
1651d169d70bSTobias Grosser 			osprintf(os, "!ptr");
1652d169d70bSTobias Grosser 		else
1653d169d70bSTobias Grosser 			osprintf(os, "%s.is_null()", name_str);
1654d169d70bSTobias Grosser 
1655d169d70bSTobias Grosser 		first = false;
1656d169d70bSTobias Grosser 	}
1657d169d70bSTobias Grosser 	if (first)
1658d169d70bSTobias Grosser 		return;
1659d169d70bSTobias Grosser 	osprintf(os, ")\n");
1660d169d70bSTobias Grosser 	print_throw_NULL_input(os);
1661d169d70bSTobias Grosser }
1662d169d70bSTobias Grosser 
1663d169d70bSTobias Grosser /* Print code for saving a copy of the isl::ctx available at the start
1664*e8227804SMichael Kruse  * of the method "method" in a "saved_ctx" variable,
1665*e8227804SMichael Kruse  * for use in exception handling.
1666d169d70bSTobias Grosser  * "kind" specifies what kind of method "method" is.
1667d169d70bSTobias Grosser  *
1668d169d70bSTobias Grosser  * If checked bindings are being generated,
1669*e8227804SMichael Kruse  * then the "saved_ctx" variable is not needed.
1670d169d70bSTobias Grosser  * If "method" is a member function, then obtain the isl_ctx from
1671d169d70bSTobias Grosser  * the "this" object.
1672*e8227804SMichael Kruse  * If the first argument of the method is an isl::ctx, then use that one.
1673d169d70bSTobias Grosser  * Otherwise, save a copy of the isl::ctx associated to the first argument
1674d169d70bSTobias Grosser  * of isl object type.
1675d169d70bSTobias Grosser  */
1676d169d70bSTobias Grosser void cpp_generator::print_save_ctx(ostream &os, FunctionDecl *method,
1677d169d70bSTobias Grosser 	function_kind kind)
1678d169d70bSTobias Grosser {
1679d169d70bSTobias Grosser 	int n;
1680d169d70bSTobias Grosser 	ParmVarDecl *param = method->getParamDecl(0);
1681d169d70bSTobias Grosser 	QualType type = param->getOriginalType();
1682d169d70bSTobias Grosser 
1683d169d70bSTobias Grosser 	if (checked)
1684d169d70bSTobias Grosser 		return;
1685d169d70bSTobias Grosser 	if (kind == function_kind_member_method) {
1686*e8227804SMichael Kruse 		osprintf(os, "  auto saved_ctx = ctx();\n");
1687d169d70bSTobias Grosser 		return;
1688d169d70bSTobias Grosser 	}
1689d169d70bSTobias Grosser 	if (is_isl_ctx(type)) {
1690d169d70bSTobias Grosser 		const char *name;
1691d169d70bSTobias Grosser 
1692d169d70bSTobias Grosser 		name = param->getName().str().c_str();
1693*e8227804SMichael Kruse 		osprintf(os, "  auto saved_ctx = %s;\n", name);
1694d169d70bSTobias Grosser 		return;
1695d169d70bSTobias Grosser 	}
1696d169d70bSTobias Grosser 	n = method->getNumParams();
1697d169d70bSTobias Grosser 	for (int i = 0; i < n; ++i) {
1698d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
1699d169d70bSTobias Grosser 		QualType type = param->getOriginalType();
1700d169d70bSTobias Grosser 
1701d169d70bSTobias Grosser 		if (!is_isl_type(type))
1702d169d70bSTobias Grosser 			continue;
1703*e8227804SMichael Kruse 		osprintf(os, "  auto saved_ctx = %s.ctx();\n",
1704d169d70bSTobias Grosser 			param->getName().str().c_str());
1705d169d70bSTobias Grosser 		return;
1706d169d70bSTobias Grosser 	}
1707d169d70bSTobias Grosser }
1708d169d70bSTobias Grosser 
1709d169d70bSTobias Grosser /* Print code to make isl not print an error message when an error occurs
1710d169d70bSTobias Grosser  * within the current scope (if exceptions are available),
1711d169d70bSTobias Grosser  * since the error message will be included in the exception.
1712d169d70bSTobias Grosser  * If exceptions are not available, then exception::on_error
1713d169d70bSTobias Grosser  * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead.
1714d169d70bSTobias Grosser  *
1715d169d70bSTobias Grosser  * If checked bindings are being generated,
1716d169d70bSTobias Grosser  * then leave it to the user to decide what isl should do on error.
1717*e8227804SMichael Kruse  * Otherwise, assume that a valid isl::ctx is available
1718*e8227804SMichael Kruse  * in the "saved_ctx" variable,
1719d169d70bSTobias Grosser  * e.g., through a prior call to print_save_ctx.
1720d169d70bSTobias Grosser  */
1721d169d70bSTobias Grosser void cpp_generator::print_on_error_continue(ostream &os)
1722d169d70bSTobias Grosser {
1723d169d70bSTobias Grosser 	if (checked)
1724d169d70bSTobias Grosser 		return;
1725*e8227804SMichael Kruse 	osprintf(os, "  options_scoped_set_on_error saved_on_error(saved_ctx, "
1726d169d70bSTobias Grosser 		     "exception::on_error);\n");
1727d169d70bSTobias Grosser }
1728d169d70bSTobias Grosser 
1729*e8227804SMichael Kruse /* Print code to "os" that checks whether any of the persistent callbacks
1730*e8227804SMichael Kruse  * of "clazz" is set and if it failed with an exception.  If so, the "eptr"
1731*e8227804SMichael Kruse  * in the corresponding data structure contains the exception
1732*e8227804SMichael Kruse  * that was caught and that needs to be rethrown.
1733*e8227804SMichael Kruse  * This field is cleared because the callback and its data may get reused.
1734*e8227804SMichael Kruse  *
1735*e8227804SMichael Kruse  * The check only needs to be generated for member methods since
1736*e8227804SMichael Kruse  * an object is needed for any of the persistent callbacks to be set.
1737*e8227804SMichael Kruse  */
1738*e8227804SMichael Kruse static void print_persistent_callback_exceptional_execution_check(ostream &os,
1739*e8227804SMichael Kruse 	const isl_class &clazz, cpp_generator::function_kind kind)
1740*e8227804SMichael Kruse {
1741*e8227804SMichael Kruse 	const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
1742*e8227804SMichael Kruse 	set<FunctionDecl *>::const_iterator in;
1743*e8227804SMichael Kruse 
1744*e8227804SMichael Kruse 	if (kind != cpp_generator::function_kind_member_method)
1745*e8227804SMichael Kruse 		return;
1746*e8227804SMichael Kruse 
1747*e8227804SMichael Kruse 	for (in = callbacks.begin(); in != callbacks.end(); ++in) {
1748*e8227804SMichael Kruse 		string callback_name = clazz.persistent_callback_name(*in);
1749*e8227804SMichael Kruse 
1750*e8227804SMichael Kruse 		osprintf(os, "  if (%s_data && %s_data->eptr) {\n",
1751*e8227804SMichael Kruse 			callback_name.c_str(), callback_name.c_str());
1752*e8227804SMichael Kruse 		osprintf(os, "    std::exception_ptr eptr = %s_data->eptr;\n",
1753*e8227804SMichael Kruse 			callback_name.c_str());
1754*e8227804SMichael Kruse 		osprintf(os, "    %s_data->eptr = nullptr;\n",
1755*e8227804SMichael Kruse 			callback_name.c_str());
1756*e8227804SMichael Kruse 		osprintf(os, "    std::rethrow_exception(eptr);\n");
1757*e8227804SMichael Kruse 		osprintf(os, "  }\n");
1758*e8227804SMichael Kruse 	}
1759*e8227804SMichael Kruse }
1760*e8227804SMichael Kruse 
1761d169d70bSTobias Grosser /* Print code that checks whether the execution of the core of "method"
1762*e8227804SMichael Kruse  * of class "clazz" was successful.
1763*e8227804SMichael Kruse  * "kind" specifies what kind of method "method" is.
1764d169d70bSTobias Grosser  *
1765d169d70bSTobias Grosser  * If checked bindings are being generated,
1766d169d70bSTobias Grosser  * then no checks are performed.
1767d169d70bSTobias Grosser  *
1768d169d70bSTobias Grosser  * Otherwise, first check if any of the callbacks failed with
1769d169d70bSTobias Grosser  * an exception.  If so, the "eptr" in the corresponding data structure
1770d169d70bSTobias Grosser  * contains the exception that was caught and that needs to be rethrown.
1771d169d70bSTobias Grosser  * Then check if the function call failed in any other way and throw
1772d169d70bSTobias Grosser  * the appropriate exception.
1773*e8227804SMichael Kruse  * In particular, if the return type is isl_stat, isl_bool or isl_size,
1774d169d70bSTobias Grosser  * then a negative value indicates a failure.  If the return type
1775d169d70bSTobias Grosser  * is an isl type, then a NULL value indicates a failure.
1776d169d70bSTobias Grosser  * Assume print_save_ctx has made sure that a valid isl::ctx
1777d169d70bSTobias Grosser  * is available in the "ctx" variable.
1778d169d70bSTobias Grosser  */
1779d169d70bSTobias Grosser void cpp_generator::print_exceptional_execution_check(ostream &os,
1780*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *method, function_kind kind)
1781d169d70bSTobias Grosser {
1782d169d70bSTobias Grosser 	int n;
1783d169d70bSTobias Grosser 	bool check_null, check_neg;
1784d169d70bSTobias Grosser 	QualType return_type = method->getReturnType();
1785d169d70bSTobias Grosser 
1786d169d70bSTobias Grosser 	if (checked)
1787d169d70bSTobias Grosser 		return;
1788d169d70bSTobias Grosser 
1789*e8227804SMichael Kruse 	print_persistent_callback_exceptional_execution_check(os, clazz, kind);
1790*e8227804SMichael Kruse 
1791d169d70bSTobias Grosser 	n = method->getNumParams();
1792d169d70bSTobias Grosser 	for (int i = 0; i < n; ++i) {
1793d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
1794d169d70bSTobias Grosser 		const char *name;
1795d169d70bSTobias Grosser 
1796d169d70bSTobias Grosser 		if (!is_callback(param->getOriginalType()))
1797d169d70bSTobias Grosser 			continue;
1798d169d70bSTobias Grosser 		name = param->getName().str().c_str();
1799d169d70bSTobias Grosser 		osprintf(os, "  if (%s_data.eptr)\n", name);
1800d169d70bSTobias Grosser 		osprintf(os, "    std::rethrow_exception(%s_data.eptr);\n",
1801d169d70bSTobias Grosser 			name);
1802d169d70bSTobias Grosser 	}
1803d169d70bSTobias Grosser 
1804*e8227804SMichael Kruse 	check_neg = is_isl_neg_error(return_type);
1805d169d70bSTobias Grosser 	check_null = is_isl_type(return_type);
1806d169d70bSTobias Grosser 	if (!check_null && !check_neg)
1807d169d70bSTobias Grosser 		return;
1808d169d70bSTobias Grosser 
1809d169d70bSTobias Grosser 	if (check_neg)
1810d169d70bSTobias Grosser 		osprintf(os, "  if (res < 0)\n");
1811d169d70bSTobias Grosser 	else
1812d169d70bSTobias Grosser 		osprintf(os, "  if (!res)\n");
1813d169d70bSTobias Grosser 	print_throw_last_error(os);
1814d169d70bSTobias Grosser }
1815d169d70bSTobias Grosser 
1816*e8227804SMichael Kruse /* Does "fd" modify an object of a subclass based on a type function?
1817*e8227804SMichael Kruse  */
1818*e8227804SMichael Kruse static bool is_subclass_mutator(const isl_class &clazz, FunctionDecl *fd)
1819*e8227804SMichael Kruse {
1820*e8227804SMichael Kruse 	return clazz.is_type_subclass() && generator::is_mutator(clazz, fd);
1821*e8227804SMichael Kruse }
1822*e8227804SMichael Kruse 
1823*e8227804SMichael Kruse /* Return the C++ return type of the method corresponding to "fd" in "clazz".
1824*e8227804SMichael Kruse  *
1825*e8227804SMichael Kruse  * If "fd" modifies an object of a subclass, then return
1826*e8227804SMichael Kruse  * the type of this subclass.
1827*e8227804SMichael Kruse  * Otherwise, return the C++ counterpart of the actual return type.
1828*e8227804SMichael Kruse  */
1829*e8227804SMichael Kruse std::string cpp_generator::get_return_type(const isl_class &clazz,
1830*e8227804SMichael Kruse 	FunctionDecl *fd)
1831*e8227804SMichael Kruse {
1832*e8227804SMichael Kruse 	if (is_subclass_mutator(clazz, fd))
1833*e8227804SMichael Kruse 		return type2cpp(clazz);
1834*e8227804SMichael Kruse 	else
1835*e8227804SMichael Kruse 		return type2cpp(fd->getReturnType());
1836*e8227804SMichael Kruse }
1837*e8227804SMichael Kruse 
1838*e8227804SMichael Kruse /* Given a function "method" for setting a "clazz" persistent callback,
1839*e8227804SMichael Kruse  * print the implementations of the methods needed for that callback.
1840*e8227804SMichael Kruse  *
1841*e8227804SMichael Kruse  * In particular, print
1842*e8227804SMichael Kruse  * - the implementation of a static inline method
1843*e8227804SMichael Kruse  *   for use as the C callback function
1844*e8227804SMichael Kruse  * - the definition of a private method for setting the callback function
1845*e8227804SMichael Kruse  * - the public method for constructing a new object with the callback set.
1846*e8227804SMichael Kruse  */
1847*e8227804SMichael Kruse void cpp_generator::print_set_persistent_callback(ostream &os,
1848*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *method,
1849*e8227804SMichael Kruse 	function_kind kind)
1850*e8227804SMichael Kruse {
1851*e8227804SMichael Kruse 	string fullname = method->getName();
1852*e8227804SMichael Kruse 	ParmVarDecl *param = persistent_callback_arg(method);
1853*e8227804SMichael Kruse 	string classname = type2cpp(clazz);
1854*e8227804SMichael Kruse 	string pname;
1855*e8227804SMichael Kruse 	string callback_name = clazz.persistent_callback_name(method);
1856*e8227804SMichael Kruse 
1857*e8227804SMichael Kruse 	osprintf(os, "\n");
1858*e8227804SMichael Kruse 	print_persistent_callback_prototype(os, clazz, method, false);
1859*e8227804SMichael Kruse 	osprintf(os, "\n");
1860*e8227804SMichael Kruse 	osprintf(os, "{\n");
1861*e8227804SMichael Kruse 	print_callback_body(os, 2, param, callback_name);
1862*e8227804SMichael Kruse 	osprintf(os, "}\n\n");
1863*e8227804SMichael Kruse 
1864*e8227804SMichael Kruse 	pname = param->getName().str();
1865*e8227804SMichael Kruse 	print_persistent_callback_setter_prototype(os, clazz, method, false);
1866*e8227804SMichael Kruse 	osprintf(os, "\n");
1867*e8227804SMichael Kruse 	osprintf(os, "{\n");
1868*e8227804SMichael Kruse 	print_check_ptr_start(os, clazz, "ptr");
1869*e8227804SMichael Kruse 	osprintf(os, "  %s_data = std::make_shared<struct %s_data>();\n",
1870*e8227804SMichael Kruse 		callback_name.c_str(), callback_name.c_str());
1871*e8227804SMichael Kruse 	osprintf(os, "  %s_data->func = %s;\n",
1872*e8227804SMichael Kruse 		callback_name.c_str(), pname.c_str());
1873*e8227804SMichael Kruse 	osprintf(os, "  ptr = %s(ptr, &%s, %s_data.get());\n",
1874*e8227804SMichael Kruse 		fullname.c_str(), callback_name.c_str(), callback_name.c_str());
1875*e8227804SMichael Kruse 	print_check_ptr_end(os, "ptr");
1876*e8227804SMichael Kruse 	osprintf(os, "}\n\n");
1877*e8227804SMichael Kruse 
1878*e8227804SMichael Kruse 	print_method_header(os, clazz, method, false, kind);
1879*e8227804SMichael Kruse 	osprintf(os, "{\n");
1880*e8227804SMichael Kruse 	osprintf(os, "  auto copy = *this;\n");
1881*e8227804SMichael Kruse 	osprintf(os, "  copy.set_%s_data(%s);\n",
1882*e8227804SMichael Kruse 		callback_name.c_str(), pname.c_str());
1883*e8227804SMichael Kruse 	osprintf(os, "  return copy;\n");
1884*e8227804SMichael Kruse 	osprintf(os, "}\n");
1885*e8227804SMichael Kruse }
1886*e8227804SMichael Kruse 
188726269d34STobias Grosser /* Print the return statement of the C++ method corresponding
188826269d34STobias Grosser  * to the C function "method" in class "clazz" to "os".
1889d169d70bSTobias Grosser  *
189026269d34STobias Grosser  * The result of the isl function is returned as a new
1891d169d70bSTobias Grosser  * object if the underlying isl function returns an isl_* ptr, as a bool
1892d169d70bSTobias Grosser  * if the isl function returns an isl_bool, as void if the isl functions
1893d169d70bSTobias Grosser  * returns an isl_stat,
1894d169d70bSTobias Grosser  * as std::string if the isl function returns 'const char *', and as
1895d169d70bSTobias Grosser  * unmodified return value otherwise.
1896d169d70bSTobias Grosser  * If checked C++ bindings are being generated,
1897d169d70bSTobias Grosser  * then an isl_bool return type is transformed into a boolean and
1898d169d70bSTobias Grosser  * an isl_stat into a stat since no exceptions can be generated
1899d169d70bSTobias Grosser  * on negative results from the isl function.
1900*e8227804SMichael Kruse  * If the method returns a new instance of the same object type and
1901*e8227804SMichael Kruse  * if the class has any persistent callbacks, then the data
1902*e8227804SMichael Kruse  * for these callbacks are copied from the original to the new object.
1903*e8227804SMichael Kruse  * If "clazz" is a subclass that is based on a type function and
1904*e8227804SMichael Kruse  * if the return type corresponds to the superclass data type,
1905*e8227804SMichael Kruse  * then it is replaced by the subclass data type.
190626269d34STobias Grosser  */
190726269d34STobias Grosser void cpp_generator::print_method_return(ostream &os, const isl_class &clazz,
190826269d34STobias Grosser 	FunctionDecl *method)
190926269d34STobias Grosser {
191026269d34STobias Grosser 	QualType return_type = method->getReturnType();
1911*e8227804SMichael Kruse 	string rettype_str = get_return_type(clazz, method);
1912*e8227804SMichael Kruse 	bool returns_super = is_subclass_mutator(clazz, method);
191326269d34STobias Grosser 
191426269d34STobias Grosser 	if (is_isl_type(return_type) ||
1915*e8227804SMichael Kruse 		    (checked && is_isl_neg_error(return_type))) {
1916*e8227804SMichael Kruse 		osprintf(os, "  return manage(res)");
1917*e8227804SMichael Kruse 		if (is_mutator(clazz, method) &&
1918*e8227804SMichael Kruse 		    clazz.has_persistent_callbacks())
1919*e8227804SMichael Kruse 			osprintf(os, ".copy_callbacks(*this)");
1920*e8227804SMichael Kruse 		if (returns_super)
1921*e8227804SMichael Kruse 			osprintf(os, ".as<%s>()", rettype_str.c_str());
1922*e8227804SMichael Kruse 		osprintf(os, ";\n");
192326269d34STobias Grosser 	} else if (is_isl_stat(return_type)) {
192426269d34STobias Grosser 		osprintf(os, "  return;\n");
192526269d34STobias Grosser 	} else if (is_string(return_type)) {
192626269d34STobias Grosser 		osprintf(os, "  std::string tmp(res);\n");
192726269d34STobias Grosser 		if (gives(method))
192826269d34STobias Grosser 			osprintf(os, "  free(res);\n");
192926269d34STobias Grosser 		osprintf(os, "  return tmp;\n");
193026269d34STobias Grosser 	} else {
193126269d34STobias Grosser 		osprintf(os, "  return res;\n");
193226269d34STobias Grosser 	}
193326269d34STobias Grosser }
193426269d34STobias Grosser 
1935*e8227804SMichael Kruse /* Return the formal parameter at position "pos" of "fd".
1936*e8227804SMichael Kruse  * However, if this parameter should be converted, as indicated
1937*e8227804SMichael Kruse  * by "convert", then return the second formal parameter
1938*e8227804SMichael Kruse  * of the conversion function instead.
193926269d34STobias Grosser  *
1940*e8227804SMichael Kruse  * If "convert" is empty, then it is assumed that
1941*e8227804SMichael Kruse  * none of the arguments should be converted.
1942d169d70bSTobias Grosser  */
1943*e8227804SMichael Kruse ParmVarDecl *cpp_generator::get_param(FunctionDecl *fd, int pos,
1944*e8227804SMichael Kruse 	const std::vector<bool> &convert)
1945d169d70bSTobias Grosser {
1946*e8227804SMichael Kruse 	ParmVarDecl *param = fd->getParamDecl(pos);
1947d169d70bSTobias Grosser 
1948*e8227804SMichael Kruse 	if (convert.size() == 0)
1949*e8227804SMichael Kruse 		return param;
1950*e8227804SMichael Kruse 	if (!convert[pos])
1951*e8227804SMichael Kruse 		return param;
1952*e8227804SMichael Kruse 	return conversions[param->getOriginalType().getTypePtr()];
1953d169d70bSTobias Grosser }
1954d169d70bSTobias Grosser 
1955*e8227804SMichael Kruse /* Print the header for "method" in class "clazz", with name "cname" and
1956*e8227804SMichael Kruse  * "num_params" number of arguments, to "os".
1957d169d70bSTobias Grosser  *
1958d169d70bSTobias Grosser  * Print the header of a declaration if "is_declaration" is set, otherwise print
1959d169d70bSTobias Grosser  * the header of a method definition.
1960d169d70bSTobias Grosser  *
1961d169d70bSTobias Grosser  * "kind" specifies the kind of method that should be generated.
1962d169d70bSTobias Grosser  *
1963*e8227804SMichael Kruse  * "convert" specifies which of the method arguments should
1964*e8227804SMichael Kruse  * be automatically converted.
1965*e8227804SMichael Kruse  *
1966d169d70bSTobias Grosser  * This function prints headers for member methods, static methods, and
1967d169d70bSTobias Grosser  * constructors, either for their declaration or definition.
1968d169d70bSTobias Grosser  *
1969d169d70bSTobias Grosser  * Member functions are declared as "const", as they do not change the current
1970d169d70bSTobias Grosser  * object, but instead create a new object. They always retrieve the first
1971d169d70bSTobias Grosser  * parameter of the original isl function from the this-pointer of the object,
1972d169d70bSTobias Grosser  * such that only starting at the second parameter the parameters of the
1973d169d70bSTobias Grosser  * original function become part of the method's interface.
1974d169d70bSTobias Grosser  *
1975d169d70bSTobias Grosser  * A function
1976d169d70bSTobias Grosser  *
1977d169d70bSTobias Grosser  * 	__isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
1978d169d70bSTobias Grosser  * 		__isl_take isl_set *s2);
1979d169d70bSTobias Grosser  *
1980d169d70bSTobias Grosser  * is translated into:
1981d169d70bSTobias Grosser  *
1982d169d70bSTobias Grosser  * 	inline set intersect(set set2) const;
1983d169d70bSTobias Grosser  *
1984d169d70bSTobias Grosser  * For static functions and constructors all parameters of the original isl
1985d169d70bSTobias Grosser  * function are exposed.
1986d169d70bSTobias Grosser  *
1987d169d70bSTobias Grosser  * Parameters that are defined as __isl_keep or are of type string, are passed
1988d169d70bSTobias Grosser  * as const reference, which allows the compiler to optimize the parameter
1989d169d70bSTobias Grosser  * transfer.
1990d169d70bSTobias Grosser  *
1991d169d70bSTobias Grosser  * Constructors are marked as explicit using the C++ keyword 'explicit' or as
1992d169d70bSTobias Grosser  * implicit using a comment in place of the explicit keyword. By annotating
1993d169d70bSTobias Grosser  * implicit constructors with a comment, users of the interface are made
1994d169d70bSTobias Grosser  * aware of the potential danger that implicit construction is possible
1995d169d70bSTobias Grosser  * for these constructors, whereas without a comment not every user would
1996d169d70bSTobias Grosser  * know that implicit construction is allowed in absence of an explicit keyword.
1997*e8227804SMichael Kruse  *
1998*e8227804SMichael Kruse  * If any of the arguments needs to be converted, then the argument
1999*e8227804SMichael Kruse  * of the method is changed to that of the source of the conversion.
2000*e8227804SMichael Kruse  * The name of the argument is, however, derived from the original
2001*e8227804SMichael Kruse  * function argument.
2002d169d70bSTobias Grosser  */
2003d169d70bSTobias Grosser void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
2004*e8227804SMichael Kruse 	FunctionDecl *method, const string &cname, int num_params,
2005*e8227804SMichael Kruse 	bool is_declaration, function_kind kind,
2006*e8227804SMichael Kruse 	const std::vector<bool> &convert)
2007d169d70bSTobias Grosser {
2008*e8227804SMichael Kruse 	string rettype_str = get_return_type(clazz, method);
2009d169d70bSTobias Grosser 	string classname = type2cpp(clazz);
2010d169d70bSTobias Grosser 	int first_param = 0;
2011d169d70bSTobias Grosser 
2012d169d70bSTobias Grosser 	if (kind == function_kind_member_method)
2013d169d70bSTobias Grosser 		first_param = 1;
2014d169d70bSTobias Grosser 
2015d169d70bSTobias Grosser 	if (is_declaration) {
2016d169d70bSTobias Grosser 		osprintf(os, "  ");
2017d169d70bSTobias Grosser 
2018d169d70bSTobias Grosser 		if (kind == function_kind_static_method)
2019d169d70bSTobias Grosser 			osprintf(os, "static ");
2020d169d70bSTobias Grosser 
2021d169d70bSTobias Grosser 		osprintf(os, "inline ");
2022d169d70bSTobias Grosser 
2023d169d70bSTobias Grosser 		if (kind == function_kind_constructor) {
2024d169d70bSTobias Grosser 			if (is_implicit_conversion(clazz, method))
2025d169d70bSTobias Grosser 				osprintf(os, "/* implicit */ ");
2026d169d70bSTobias Grosser 			else
2027d169d70bSTobias Grosser 				osprintf(os, "explicit ");
2028d169d70bSTobias Grosser 		}
2029d169d70bSTobias Grosser 	}
2030d169d70bSTobias Grosser 
2031d169d70bSTobias Grosser 	if (kind != function_kind_constructor)
2032d169d70bSTobias Grosser 		osprintf(os, "%s ", rettype_str.c_str());
2033d169d70bSTobias Grosser 
2034d169d70bSTobias Grosser 	if (!is_declaration)
2035d169d70bSTobias Grosser 		osprintf(os, "%s::", classname.c_str());
2036d169d70bSTobias Grosser 
2037d169d70bSTobias Grosser 	if (kind != function_kind_constructor)
2038d169d70bSTobias Grosser 		osprintf(os, "%s", cname.c_str());
2039d169d70bSTobias Grosser 	else
2040d169d70bSTobias Grosser 		osprintf(os, "%s", classname.c_str());
2041d169d70bSTobias Grosser 
2042d169d70bSTobias Grosser 	osprintf(os, "(");
2043d169d70bSTobias Grosser 
2044d169d70bSTobias Grosser 	for (int i = first_param; i < num_params; ++i) {
2045*e8227804SMichael Kruse 		std::string name = method->getParamDecl(i)->getName().str();
2046*e8227804SMichael Kruse 		ParmVarDecl *param = get_param(method, i, convert);
2047d169d70bSTobias Grosser 		QualType type = param->getOriginalType();
2048d169d70bSTobias Grosser 		string cpptype = type2cpp(type);
2049d169d70bSTobias Grosser 
2050d169d70bSTobias Grosser 		if (is_callback(type))
2051d169d70bSTobias Grosser 			num_params--;
2052d169d70bSTobias Grosser 
2053d169d70bSTobias Grosser 		if (keeps(param) || is_string(type) || is_callback(type))
2054d169d70bSTobias Grosser 			osprintf(os, "const %s &%s", cpptype.c_str(),
2055*e8227804SMichael Kruse 				 name.c_str());
2056d169d70bSTobias Grosser 		else
2057*e8227804SMichael Kruse 			osprintf(os, "%s %s", cpptype.c_str(), name.c_str());
2058d169d70bSTobias Grosser 
2059d169d70bSTobias Grosser 		if (i != num_params - 1)
2060d169d70bSTobias Grosser 			osprintf(os, ", ");
2061d169d70bSTobias Grosser 	}
2062d169d70bSTobias Grosser 
2063d169d70bSTobias Grosser 	osprintf(os, ")");
2064d169d70bSTobias Grosser 
2065d169d70bSTobias Grosser 	if (kind == function_kind_member_method)
2066d169d70bSTobias Grosser 		osprintf(os, " const");
2067d169d70bSTobias Grosser 
2068d169d70bSTobias Grosser 	if (is_declaration)
2069d169d70bSTobias Grosser 		osprintf(os, ";");
2070d169d70bSTobias Grosser 	osprintf(os, "\n");
2071d169d70bSTobias Grosser }
2072d169d70bSTobias Grosser 
2073*e8227804SMichael Kruse /* Print the header for a method called "name" in class "clazz"
2074*e8227804SMichael Kruse  * derived from "method" to "os".
2075*e8227804SMichael Kruse  *
2076*e8227804SMichael Kruse  * Print the header of a declaration if "is_declaration" is set, otherwise print
2077*e8227804SMichael Kruse  * the header of a method definition.
2078*e8227804SMichael Kruse  *
2079*e8227804SMichael Kruse  * "kind" specifies the kind of method that should be generated.
2080*e8227804SMichael Kruse  *
2081*e8227804SMichael Kruse  * "convert" specifies which of the method arguments should
2082*e8227804SMichael Kruse  * be automatically converted.
2083*e8227804SMichael Kruse  */
2084*e8227804SMichael Kruse void cpp_generator::print_named_method_header(ostream &os,
2085*e8227804SMichael Kruse 	const isl_class &clazz, FunctionDecl *method, string name,
2086*e8227804SMichael Kruse 	bool is_declaration, function_kind kind,
2087*e8227804SMichael Kruse 	const std::vector<bool> &convert)
2088*e8227804SMichael Kruse {
2089*e8227804SMichael Kruse 	int num_params = method->getNumParams();
2090*e8227804SMichael Kruse 
2091*e8227804SMichael Kruse 	name = rename_method(name);
2092*e8227804SMichael Kruse 	print_method_header(os, clazz, method, name, num_params,
2093*e8227804SMichael Kruse 			    is_declaration, kind, convert);
2094*e8227804SMichael Kruse }
2095*e8227804SMichael Kruse 
2096*e8227804SMichael Kruse /* Print the header for "method" in class "clazz" to "os"
2097*e8227804SMichael Kruse  * using its default name.
2098*e8227804SMichael Kruse  *
2099*e8227804SMichael Kruse  * Print the header of a declaration if "is_declaration" is set, otherwise print
2100*e8227804SMichael Kruse  * the header of a method definition.
2101*e8227804SMichael Kruse  *
2102*e8227804SMichael Kruse  * "kind" specifies the kind of method that should be generated.
2103*e8227804SMichael Kruse  */
2104*e8227804SMichael Kruse void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
2105*e8227804SMichael Kruse 	FunctionDecl *method, bool is_declaration, function_kind kind)
2106*e8227804SMichael Kruse {
2107*e8227804SMichael Kruse 	string name = clazz.method_name(method);
2108*e8227804SMichael Kruse 
2109*e8227804SMichael Kruse 	print_named_method_header(os, clazz, method, name, is_declaration,
2110*e8227804SMichael Kruse 				  kind);
2111*e8227804SMichael Kruse }
2112*e8227804SMichael Kruse 
2113d169d70bSTobias Grosser /* Generate the list of argument types for a callback function of
2114d169d70bSTobias Grosser  * type "type".  If "cpp" is set, then generate the C++ type list, otherwise
2115d169d70bSTobias Grosser  * the C type list.
2116d169d70bSTobias Grosser  *
2117d169d70bSTobias Grosser  * For a callback of type
2118d169d70bSTobias Grosser  *
2119d169d70bSTobias Grosser  *      isl_stat (*)(__isl_take isl_map *map, void *user)
2120d169d70bSTobias Grosser  *
2121d169d70bSTobias Grosser  * the following C++ argument list is generated:
2122d169d70bSTobias Grosser  *
2123d169d70bSTobias Grosser  *      map
2124d169d70bSTobias Grosser  */
2125d169d70bSTobias Grosser string cpp_generator::generate_callback_args(QualType type, bool cpp)
2126d169d70bSTobias Grosser {
2127d169d70bSTobias Grosser 	std::string type_str;
2128d169d70bSTobias Grosser 	const FunctionProtoType *callback;
2129d169d70bSTobias Grosser 	int num_params;
2130d169d70bSTobias Grosser 
213126269d34STobias Grosser 	callback = extract_prototype(type);
2132d169d70bSTobias Grosser 	num_params = callback->getNumArgs();
2133d169d70bSTobias Grosser 	if (cpp)
2134d169d70bSTobias Grosser 		num_params--;
2135d169d70bSTobias Grosser 
2136d169d70bSTobias Grosser 	for (long i = 0; i < num_params; i++) {
2137d169d70bSTobias Grosser 		QualType type = callback->getArgType(i);
2138d169d70bSTobias Grosser 
2139d169d70bSTobias Grosser 		if (cpp)
2140d169d70bSTobias Grosser 			type_str += type2cpp(type);
2141d169d70bSTobias Grosser 		else
2142d169d70bSTobias Grosser 			type_str += type.getAsString();
2143d169d70bSTobias Grosser 
2144d169d70bSTobias Grosser 		if (!cpp)
2145d169d70bSTobias Grosser 			type_str += "arg_" + ::to_string(i);
2146d169d70bSTobias Grosser 
2147d169d70bSTobias Grosser 		if (i != num_params - 1)
2148d169d70bSTobias Grosser 			type_str += ", ";
2149d169d70bSTobias Grosser 	}
2150d169d70bSTobias Grosser 
2151d169d70bSTobias Grosser 	return type_str;
2152d169d70bSTobias Grosser }
2153d169d70bSTobias Grosser 
2154d169d70bSTobias Grosser /* Generate the full cpp type of a callback function of type "type".
2155d169d70bSTobias Grosser  *
2156d169d70bSTobias Grosser  * For a callback of type
2157d169d70bSTobias Grosser  *
2158d169d70bSTobias Grosser  *      isl_stat (*)(__isl_take isl_map *map, void *user)
2159d169d70bSTobias Grosser  *
2160d169d70bSTobias Grosser  * the following type is generated:
2161d169d70bSTobias Grosser  *
2162d169d70bSTobias Grosser  *      std::function<stat(map)>
2163d169d70bSTobias Grosser  */
2164d169d70bSTobias Grosser string cpp_generator::generate_callback_type(QualType type)
2165d169d70bSTobias Grosser {
2166d169d70bSTobias Grosser 	std::string type_str;
216726269d34STobias Grosser 	const FunctionProtoType *callback = extract_prototype(type);
2168d169d70bSTobias Grosser 	QualType return_type = callback->getReturnType();
2169d169d70bSTobias Grosser 	string rettype_str = type2cpp(return_type);
2170d169d70bSTobias Grosser 
2171d169d70bSTobias Grosser 	type_str = "std::function<";
2172d169d70bSTobias Grosser 	type_str += rettype_str;
2173d169d70bSTobias Grosser 	type_str += "(";
2174d169d70bSTobias Grosser 	type_str += generate_callback_args(type, true);
2175d169d70bSTobias Grosser 	type_str += ")>";
2176d169d70bSTobias Grosser 
2177d169d70bSTobias Grosser 	return type_str;
2178d169d70bSTobias Grosser }
2179d169d70bSTobias Grosser 
2180*e8227804SMichael Kruse /* Print the call to the C++ callback function "call",
2181*e8227804SMichael Kruse  * with the given indentation, wrapped
2182d169d70bSTobias Grosser  * for use inside the lambda function that is used as the C callback function,
2183d169d70bSTobias Grosser  * in the case where checked C++ bindings are being generated.
2184d169d70bSTobias Grosser  *
2185d169d70bSTobias Grosser  * In particular, print
2186d169d70bSTobias Grosser  *
2187*e8227804SMichael Kruse  *        auto ret = @call@;
2188d169d70bSTobias Grosser  *        return ret.release();
2189d169d70bSTobias Grosser  */
2190*e8227804SMichael Kruse void cpp_generator::print_wrapped_call_checked(ostream &os, int indent,
2191d169d70bSTobias Grosser 	const string &call)
2192d169d70bSTobias Grosser {
2193*e8227804SMichael Kruse 	osprintf(os, indent, "auto ret = %s;\n", call.c_str());
2194*e8227804SMichael Kruse 	osprintf(os, indent, "return ret.release();\n");
2195d169d70bSTobias Grosser }
2196d169d70bSTobias Grosser 
2197*e8227804SMichael Kruse /* Print the call to the C++ callback function "call",
2198*e8227804SMichael Kruse  * with the given indentation and with return type "rtype", wrapped
2199d169d70bSTobias Grosser  * for use inside the lambda function that is used as the C callback function.
2200d169d70bSTobias Grosser  *
2201d169d70bSTobias Grosser  * In particular, print
2202d169d70bSTobias Grosser  *
2203d169d70bSTobias Grosser  *        ISL_CPP_TRY {
2204d169d70bSTobias Grosser  *          @call@;
2205d169d70bSTobias Grosser  *          return isl_stat_ok;
2206d169d70bSTobias Grosser  *        } ISL_CPP_CATCH_ALL {
2207d169d70bSTobias Grosser  *          data->eptr = std::current_exception();
2208d169d70bSTobias Grosser  *          return isl_stat_error;
2209d169d70bSTobias Grosser  *        }
2210*e8227804SMichael Kruse  * or
2211*e8227804SMichael Kruse  *        ISL_CPP_TRY {
2212*e8227804SMichael Kruse  *          auto ret = @call@;
2213*e8227804SMichael Kruse  *          return ret ? isl_bool_true : isl_bool_false;
2214*e8227804SMichael Kruse  *        } ISL_CPP_CATCH_ALL {
2215*e8227804SMichael Kruse  *          data->eptr = std::current_exception();
2216*e8227804SMichael Kruse  *          return isl_bool_error;
2217*e8227804SMichael Kruse  *        }
2218*e8227804SMichael Kruse  * or
2219*e8227804SMichael Kruse  *        ISL_CPP_TRY {
2220*e8227804SMichael Kruse  *          auto ret = @call@;
2221*e8227804SMichael Kruse  *          return ret.release();
2222*e8227804SMichael Kruse  *        } ISL_CPP_CATCH_ALL {
2223*e8227804SMichael Kruse  *          data->eptr = std::current_exception();
2224*e8227804SMichael Kruse  *          return NULL;
2225*e8227804SMichael Kruse  *        }
2226*e8227804SMichael Kruse  *
2227*e8227804SMichael Kruse  * depending on the return type.
2228d169d70bSTobias Grosser  *
2229d169d70bSTobias Grosser  * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)"
2230d169d70bSTobias Grosser  * (if exceptions are available).
2231d169d70bSTobias Grosser  *
2232d169d70bSTobias Grosser  * If checked C++ bindings are being generated, then
2233d169d70bSTobias Grosser  * the call is wrapped differently.
2234d169d70bSTobias Grosser  */
2235*e8227804SMichael Kruse void cpp_generator::print_wrapped_call(ostream &os, int indent,
2236*e8227804SMichael Kruse 	const string &call, QualType rtype)
2237d169d70bSTobias Grosser {
2238d169d70bSTobias Grosser 	if (checked)
2239*e8227804SMichael Kruse 		return print_wrapped_call_checked(os, indent, call);
2240d169d70bSTobias Grosser 
2241*e8227804SMichael Kruse 	osprintf(os, indent, "ISL_CPP_TRY {\n");
2242*e8227804SMichael Kruse 	if (is_isl_stat(rtype))
2243*e8227804SMichael Kruse 		osprintf(os, indent, "  %s;\n", call.c_str());
2244*e8227804SMichael Kruse 	else
2245*e8227804SMichael Kruse 		osprintf(os, indent, "  auto ret = %s;\n", call.c_str());
2246*e8227804SMichael Kruse 	if (is_isl_stat(rtype))
2247*e8227804SMichael Kruse 		osprintf(os, indent, "  return isl_stat_ok;\n");
2248*e8227804SMichael Kruse 	else if (is_isl_bool(rtype))
2249*e8227804SMichael Kruse 		osprintf(os, indent,
2250*e8227804SMichael Kruse 			"  return ret ? isl_bool_true : isl_bool_false;\n");
2251*e8227804SMichael Kruse 	else
2252*e8227804SMichael Kruse 		osprintf(os, indent, "  return ret.release();\n");
2253*e8227804SMichael Kruse 	osprintf(os, indent, "} ISL_CPP_CATCH_ALL {\n");
2254*e8227804SMichael Kruse 	osprintf(os, indent, "  data->eptr = std::current_exception();\n");
2255*e8227804SMichael Kruse 	if (is_isl_stat(rtype))
2256*e8227804SMichael Kruse 		osprintf(os, indent, "  return isl_stat_error;\n");
2257*e8227804SMichael Kruse 	else if (is_isl_bool(rtype))
2258*e8227804SMichael Kruse 		osprintf(os, indent, "  return isl_bool_error;\n");
2259*e8227804SMichael Kruse 	else
2260*e8227804SMichael Kruse 		osprintf(os, indent, "  return NULL;\n");
2261*e8227804SMichael Kruse 	osprintf(os, indent, "}\n");
2262*e8227804SMichael Kruse }
2263*e8227804SMichael Kruse 
2264*e8227804SMichael Kruse /* Print the declaration for a "prefix"_data data structure
2265*e8227804SMichael Kruse  * that can be used for passing to a C callback function
2266*e8227804SMichael Kruse  * containing a copy of the C++ callback function "param",
2267*e8227804SMichael Kruse  * along with an std::exception_ptr that is used to store any
2268*e8227804SMichael Kruse  * exceptions thrown in the C++ callback.
2269*e8227804SMichael Kruse  *
2270*e8227804SMichael Kruse  * If the C callback is of the form
2271*e8227804SMichael Kruse  *
2272*e8227804SMichael Kruse  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
2273*e8227804SMichael Kruse  *
2274*e8227804SMichael Kruse  * then the following declaration is printed:
2275*e8227804SMichael Kruse  *
2276*e8227804SMichael Kruse  *      struct <prefix>_data {
2277*e8227804SMichael Kruse  *        std::function<stat(map)> func;
2278*e8227804SMichael Kruse  *        std::exception_ptr eptr;
2279*e8227804SMichael Kruse  *      }
2280*e8227804SMichael Kruse  *
2281*e8227804SMichael Kruse  * (without a newline or a semicolon).
2282*e8227804SMichael Kruse  *
2283*e8227804SMichael Kruse  * The std::exception_ptr object is not added to "prefix"_data
2284*e8227804SMichael Kruse  * if checked C++ bindings are being generated.
2285*e8227804SMichael Kruse  */
2286*e8227804SMichael Kruse void cpp_generator::print_callback_data_decl(ostream &os, ParmVarDecl *param,
2287*e8227804SMichael Kruse 	const string &prefix)
2288*e8227804SMichael Kruse {
2289*e8227804SMichael Kruse 	string cpp_args;
2290*e8227804SMichael Kruse 
2291*e8227804SMichael Kruse 	cpp_args = generate_callback_type(param->getType());
2292*e8227804SMichael Kruse 
2293*e8227804SMichael Kruse 	osprintf(os, "  struct %s_data {\n", prefix.c_str());
2294*e8227804SMichael Kruse 	osprintf(os, "    %s func;\n", cpp_args.c_str());
2295*e8227804SMichael Kruse 	if (!checked)
2296*e8227804SMichael Kruse 		osprintf(os, "    std::exception_ptr eptr;\n");
2297*e8227804SMichael Kruse 	osprintf(os, "  }");
2298*e8227804SMichael Kruse }
2299*e8227804SMichael Kruse 
2300*e8227804SMichael Kruse /* Print the body of C function callback with the given indentation
2301*e8227804SMichael Kruse  * that can be use as an argument to "param" for marshalling
2302*e8227804SMichael Kruse  * the corresponding C++ callback.
2303*e8227804SMichael Kruse  * The data structure that contains the C++ callback is of type
2304*e8227804SMichael Kruse  * "prefix"_data.
2305*e8227804SMichael Kruse  *
2306*e8227804SMichael Kruse  * For a callback of the form
2307*e8227804SMichael Kruse  *
2308*e8227804SMichael Kruse  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
2309*e8227804SMichael Kruse  *
2310*e8227804SMichael Kruse  * the following code is generated:
2311*e8227804SMichael Kruse  *
2312*e8227804SMichael Kruse  *        auto *data = static_cast<struct <prefix>_data *>(arg_1);
2313*e8227804SMichael Kruse  *        ISL_CPP_TRY {
2314*e8227804SMichael Kruse  *          stat ret = (data->func)(manage(arg_0));
2315*e8227804SMichael Kruse  *          return isl_stat_ok;
2316*e8227804SMichael Kruse  *        } ISL_CPP_CATCH_ALL {
2317*e8227804SMichael Kruse  *          data->eptr = std::current_exception();
2318*e8227804SMichael Kruse  *          return isl_stat_error;
2319*e8227804SMichael Kruse  *        }
2320*e8227804SMichael Kruse  *
2321*e8227804SMichael Kruse  * If checked C++ bindings are being generated, then
2322*e8227804SMichael Kruse  * generate the following code:
2323*e8227804SMichael Kruse  *
2324*e8227804SMichael Kruse  *        auto *data = static_cast<struct <prefix>_data *>(arg_1);
2325*e8227804SMichael Kruse  *        stat ret = (data->func)(manage(arg_0));
2326*e8227804SMichael Kruse  *        return isl_stat(ret);
2327*e8227804SMichael Kruse  */
2328*e8227804SMichael Kruse void cpp_generator::print_callback_body(ostream &os, int indent,
2329*e8227804SMichael Kruse 	ParmVarDecl *param, const string &prefix)
2330*e8227804SMichael Kruse {
2331*e8227804SMichael Kruse 	QualType ptype, rtype;
2332*e8227804SMichael Kruse 	string call, last_idx;
2333*e8227804SMichael Kruse 	const FunctionProtoType *callback;
2334*e8227804SMichael Kruse 	int num_params;
2335*e8227804SMichael Kruse 
2336*e8227804SMichael Kruse 	ptype = param->getType();
2337*e8227804SMichael Kruse 
2338*e8227804SMichael Kruse 	callback = extract_prototype(ptype);
2339*e8227804SMichael Kruse 	rtype = callback->getReturnType();
2340*e8227804SMichael Kruse 	num_params = callback->getNumArgs();
2341*e8227804SMichael Kruse 
2342*e8227804SMichael Kruse 	last_idx = ::to_string(num_params - 1);
2343*e8227804SMichael Kruse 
2344*e8227804SMichael Kruse 	call = "(data->func)(";
2345*e8227804SMichael Kruse 	for (long i = 0; i < num_params - 1; i++) {
2346*e8227804SMichael Kruse 		if (!callback_takes_argument(param, i))
2347*e8227804SMichael Kruse 			call += "manage_copy";
2348*e8227804SMichael Kruse 		else
2349*e8227804SMichael Kruse 			call += "manage";
2350*e8227804SMichael Kruse 		call += "(arg_" + ::to_string(i) + ")";
2351*e8227804SMichael Kruse 		if (i != num_params - 2)
2352*e8227804SMichael Kruse 			call += ", ";
2353*e8227804SMichael Kruse 	}
2354*e8227804SMichael Kruse 	call += ")";
2355*e8227804SMichael Kruse 
2356*e8227804SMichael Kruse 	osprintf(os, indent,
2357*e8227804SMichael Kruse 		 "auto *data = static_cast<struct %s_data *>(arg_%s);\n",
2358*e8227804SMichael Kruse 		 prefix.c_str(), last_idx.c_str());
2359*e8227804SMichael Kruse 	print_wrapped_call(os, indent, call, rtype);
2360d169d70bSTobias Grosser }
2361d169d70bSTobias Grosser 
2362d169d70bSTobias Grosser /* Print the local variables that are needed for a callback argument,
2363d169d70bSTobias Grosser  * in particular, print a lambda function that wraps the callback and
2364d169d70bSTobias Grosser  * a pointer to the actual C++ callback function.
2365d169d70bSTobias Grosser  *
2366d169d70bSTobias Grosser  * For a callback of the form
2367d169d70bSTobias Grosser  *
2368d169d70bSTobias Grosser  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
2369d169d70bSTobias Grosser  *
2370d169d70bSTobias Grosser  * the following lambda function is generated:
2371d169d70bSTobias Grosser  *
2372d169d70bSTobias Grosser  *      auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
2373d169d70bSTobias Grosser  *        auto *data = static_cast<struct fn_data *>(arg_1);
2374d169d70bSTobias Grosser  *        try {
2375*e8227804SMichael Kruse  *          stat ret = (data->func)(manage(arg_0));
2376d169d70bSTobias Grosser  *          return isl_stat_ok;
2377d169d70bSTobias Grosser  *        } catch (...) {
2378d169d70bSTobias Grosser  *          data->eptr = std::current_exception();
2379d169d70bSTobias Grosser  *          return isl_stat_error;
2380d169d70bSTobias Grosser  *        }
2381d169d70bSTobias Grosser  *      };
2382d169d70bSTobias Grosser  *
2383*e8227804SMichael Kruse  * A copy of the std::function C++ callback function is stored in
2384d169d70bSTobias Grosser  * a fn_data data structure for passing to the C callback function,
2385d169d70bSTobias Grosser  * along with an std::exception_ptr that is used to store any
2386d169d70bSTobias Grosser  * exceptions thrown in the C++ callback.
2387d169d70bSTobias Grosser  *
2388d169d70bSTobias Grosser  *      struct fn_data {
2389*e8227804SMichael Kruse  *        std::function<stat(map)> func;
2390d169d70bSTobias Grosser  *        std::exception_ptr eptr;
2391*e8227804SMichael Kruse  *      } fn_data = { fn };
2392d169d70bSTobias Grosser  *
2393d169d70bSTobias Grosser  * This std::function object represents the actual user
2394d169d70bSTobias Grosser  * callback function together with the locally captured state at the caller.
2395d169d70bSTobias Grosser  *
2396d169d70bSTobias Grosser  * The lambda function is expected to be used as a C callback function
2397d169d70bSTobias Grosser  * where the lambda itself is provided as the function pointer and
2398d169d70bSTobias Grosser  * where the user void pointer is a pointer to fn_data.
2399d169d70bSTobias Grosser  * The std::function object is extracted from the pointer to fn_data
2400d169d70bSTobias Grosser  * inside the lambda function.
2401d169d70bSTobias Grosser  *
2402d169d70bSTobias Grosser  * The std::exception_ptr object is not added to fn_data
2403d169d70bSTobias Grosser  * if checked C++ bindings are being generated.
2404d169d70bSTobias Grosser  * The body of the generated lambda function then is as follows:
2405d169d70bSTobias Grosser  *
2406*e8227804SMichael Kruse  *        stat ret = (data->func)(manage(arg_0));
2407d169d70bSTobias Grosser  *        return isl_stat(ret);
24086145b11cSTobias Grosser  *
24096145b11cSTobias Grosser  * If the C callback does not take its arguments, then
24106145b11cSTobias Grosser  * manage_copy is used instead of manage.
2411d169d70bSTobias Grosser  */
2412d169d70bSTobias Grosser void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param)
2413d169d70bSTobias Grosser {
2414d169d70bSTobias Grosser 	string pname;
2415*e8227804SMichael Kruse 	QualType ptype, rtype;
2416*e8227804SMichael Kruse 	string c_args, cpp_args, rettype;
2417d169d70bSTobias Grosser 	const FunctionProtoType *callback;
2418d169d70bSTobias Grosser 
2419d169d70bSTobias Grosser 	pname = param->getName().str();
2420d169d70bSTobias Grosser 	ptype = param->getType();
2421d169d70bSTobias Grosser 
2422d169d70bSTobias Grosser 	c_args = generate_callback_args(ptype, false);
2423d169d70bSTobias Grosser 
242426269d34STobias Grosser 	callback = extract_prototype(ptype);
2425*e8227804SMichael Kruse 	rtype = callback->getReturnType();
2426*e8227804SMichael Kruse 	rettype = rtype.getAsString();
2427d169d70bSTobias Grosser 
2428*e8227804SMichael Kruse 	print_callback_data_decl(os, param, pname);
2429*e8227804SMichael Kruse 	osprintf(os, " %s_data = { %s };\n", pname.c_str(), pname.c_str());
2430d169d70bSTobias Grosser 	osprintf(os, "  auto %s_lambda = [](%s) -> %s {\n",
2431d169d70bSTobias Grosser 		 pname.c_str(), c_args.c_str(), rettype.c_str());
2432*e8227804SMichael Kruse 	print_callback_body(os, 4, param, pname);
2433d169d70bSTobias Grosser 	osprintf(os, "  };\n");
2434d169d70bSTobias Grosser }
2435d169d70bSTobias Grosser 
2436d169d70bSTobias Grosser /* An array listing functions that must be renamed and the function name they
2437d169d70bSTobias Grosser  * should be renamed to. We currently rename functions in case their name would
2438d169d70bSTobias Grosser  * match a reserved C++ keyword, which is not allowed in C++.
2439d169d70bSTobias Grosser  */
2440d169d70bSTobias Grosser static const char *rename_map[][2] = {
2441d169d70bSTobias Grosser 	{ "union", "unite" },
2442d169d70bSTobias Grosser };
2443d169d70bSTobias Grosser 
2444d169d70bSTobias Grosser /* Rename method "name" in case the method name in the C++ bindings should not
2445d169d70bSTobias Grosser  * match the name in the C bindings. We do this for example to avoid
2446d169d70bSTobias Grosser  * C++ keywords.
2447d169d70bSTobias Grosser  */
2448d169d70bSTobias Grosser std::string cpp_generator::rename_method(std::string name)
2449d169d70bSTobias Grosser {
2450d169d70bSTobias Grosser 	for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++)
2451d169d70bSTobias Grosser 		if (name.compare(rename_map[i][0]) == 0)
2452d169d70bSTobias Grosser 			return rename_map[i][1];
2453d169d70bSTobias Grosser 
2454d169d70bSTobias Grosser 	return name;
2455d169d70bSTobias Grosser }
2456d169d70bSTobias Grosser 
2457d169d70bSTobias Grosser /* Translate isl class "clazz" to its corresponding C++ type.
2458*e8227804SMichael Kruse  * Use the name of the type based subclass, if any.
2459d169d70bSTobias Grosser  */
2460d169d70bSTobias Grosser string cpp_generator::type2cpp(const isl_class &clazz)
2461d169d70bSTobias Grosser {
2462*e8227804SMichael Kruse 	return type2cpp(clazz.subclass_name);
2463d169d70bSTobias Grosser }
2464d169d70bSTobias Grosser 
2465d169d70bSTobias Grosser /* Translate type string "type_str" to its C++ name counterpart.
2466d169d70bSTobias Grosser */
2467d169d70bSTobias Grosser string cpp_generator::type2cpp(string type_str)
2468d169d70bSTobias Grosser {
2469d169d70bSTobias Grosser 	return type_str.substr(4);
2470d169d70bSTobias Grosser }
2471d169d70bSTobias Grosser 
2472*e8227804SMichael Kruse /* Return the C++ counterpart to the isl_bool type.
2473*e8227804SMichael Kruse  * If checked C++ bindings are being generated,
2474*e8227804SMichael Kruse  * then this is "boolean".  Otherwise, it is simply "bool".
2475*e8227804SMichael Kruse  */
2476*e8227804SMichael Kruse string cpp_generator::isl_bool2cpp()
2477*e8227804SMichael Kruse {
2478*e8227804SMichael Kruse 	return checked ? "boolean" : "bool";
2479*e8227804SMichael Kruse }
2480*e8227804SMichael Kruse 
2481*e8227804SMichael Kruse /* Return the namespace of the generated C++ bindings.
2482*e8227804SMichael Kruse  */
2483*e8227804SMichael Kruse string cpp_generator::isl_namespace()
2484*e8227804SMichael Kruse {
2485*e8227804SMichael Kruse 	return checked ? "isl::checked::" : "isl::";
2486*e8227804SMichael Kruse }
2487*e8227804SMichael Kruse 
2488d169d70bSTobias Grosser /* Translate QualType "type" to its C++ name counterpart.
2489d169d70bSTobias Grosser  *
2490d169d70bSTobias Grosser  * An isl_bool return type is translated into "bool",
2491*e8227804SMichael Kruse  * while an isl_stat is translated into "void" and
2492*e8227804SMichael Kruse  * an isl_size is translated to "unsigned".
2493d169d70bSTobias Grosser  * The exceptional cases are handled through exceptions.
2494d169d70bSTobias Grosser  * If checked C++ bindings are being generated, then
2495*e8227804SMichael Kruse  * C++ counterparts of isl_bool, isl_stat and isl_size need to be used instead.
2496d169d70bSTobias Grosser  */
2497d169d70bSTobias Grosser string cpp_generator::type2cpp(QualType type)
2498d169d70bSTobias Grosser {
2499d169d70bSTobias Grosser 	if (is_isl_type(type))
2500*e8227804SMichael Kruse 		return isl_namespace() +
2501*e8227804SMichael Kruse 				type2cpp(type->getPointeeType().getAsString());
2502d169d70bSTobias Grosser 
2503d169d70bSTobias Grosser 	if (is_isl_bool(type))
2504*e8227804SMichael Kruse 		return isl_bool2cpp();
2505d169d70bSTobias Grosser 
2506d169d70bSTobias Grosser 	if (is_isl_stat(type))
2507d169d70bSTobias Grosser 		return checked ? "stat" : "void";
2508d169d70bSTobias Grosser 
2509*e8227804SMichael Kruse 	if (is_isl_size(type))
2510*e8227804SMichael Kruse 		return checked ? "class size" : "unsigned";
2511*e8227804SMichael Kruse 
2512d169d70bSTobias Grosser 	if (type->isIntegerType())
2513d169d70bSTobias Grosser 		return type.getAsString();
2514d169d70bSTobias Grosser 
2515d169d70bSTobias Grosser 	if (is_string(type))
2516d169d70bSTobias Grosser 		return "std::string";
2517d169d70bSTobias Grosser 
2518d169d70bSTobias Grosser 	if (is_callback(type))
2519d169d70bSTobias Grosser 		return generate_callback_type(type);
2520d169d70bSTobias Grosser 
2521d169d70bSTobias Grosser 	die("Cannot convert type to C++ type");
2522d169d70bSTobias Grosser }
2523d169d70bSTobias Grosser 
2524d169d70bSTobias Grosser /* Check if "subclass_type" is a subclass of "class_type".
2525d169d70bSTobias Grosser  */
2526d169d70bSTobias Grosser bool cpp_generator::is_subclass(QualType subclass_type,
2527d169d70bSTobias Grosser 	const isl_class &class_type)
2528d169d70bSTobias Grosser {
2529d169d70bSTobias Grosser 	std::string type_str = subclass_type->getPointeeType().getAsString();
2530d169d70bSTobias Grosser 	std::vector<std::string> superclasses;
2531d169d70bSTobias Grosser 	std::vector<const isl_class *> parents;
2532d169d70bSTobias Grosser 	std::vector<std::string>::iterator ci;
2533d169d70bSTobias Grosser 
2534d169d70bSTobias Grosser 	superclasses = generator::find_superclasses(classes[type_str].type);
2535d169d70bSTobias Grosser 
2536d169d70bSTobias Grosser 	for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
2537d169d70bSTobias Grosser 		parents.push_back(&classes[*ci]);
2538d169d70bSTobias Grosser 
2539d169d70bSTobias Grosser 	while (!parents.empty()) {
2540d169d70bSTobias Grosser 		const isl_class *candidate = parents.back();
2541d169d70bSTobias Grosser 
2542d169d70bSTobias Grosser 		parents.pop_back();
2543d169d70bSTobias Grosser 
2544d169d70bSTobias Grosser 		if (&class_type == candidate)
2545d169d70bSTobias Grosser 			return true;
2546d169d70bSTobias Grosser 
2547d169d70bSTobias Grosser 		superclasses = generator::find_superclasses(candidate->type);
2548d169d70bSTobias Grosser 
2549d169d70bSTobias Grosser 		for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
2550d169d70bSTobias Grosser 			parents.push_back(&classes[*ci]);
2551d169d70bSTobias Grosser 	}
2552d169d70bSTobias Grosser 
2553d169d70bSTobias Grosser 	return false;
2554d169d70bSTobias Grosser }
2555d169d70bSTobias Grosser 
2556d169d70bSTobias Grosser /* Check if "cons" is an implicit conversion constructor of class "clazz".
2557d169d70bSTobias Grosser  *
2558d169d70bSTobias Grosser  * An implicit conversion constructor is generated in case "cons" has a single
2559d169d70bSTobias Grosser  * parameter, where the parameter type is a subclass of the class that is
2560d169d70bSTobias Grosser  * currently being generated.
2561d169d70bSTobias Grosser  */
2562d169d70bSTobias Grosser bool cpp_generator::is_implicit_conversion(const isl_class &clazz,
2563d169d70bSTobias Grosser 	FunctionDecl *cons)
2564d169d70bSTobias Grosser {
2565d169d70bSTobias Grosser 	ParmVarDecl *param = cons->getParamDecl(0);
2566d169d70bSTobias Grosser 	QualType type = param->getOriginalType();
2567d169d70bSTobias Grosser 
2568d169d70bSTobias Grosser 	int num_params = cons->getNumParams();
2569d169d70bSTobias Grosser 	if (num_params != 1)
2570d169d70bSTobias Grosser 		return false;
2571d169d70bSTobias Grosser 
2572d169d70bSTobias Grosser 	if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz))
2573d169d70bSTobias Grosser 		return true;
2574d169d70bSTobias Grosser 
2575d169d70bSTobias Grosser 	return false;
2576d169d70bSTobias Grosser }
2577d169d70bSTobias Grosser 
2578d169d70bSTobias Grosser /* Get kind of "method" in "clazz".
2579d169d70bSTobias Grosser  *
2580d169d70bSTobias Grosser  * Given the declaration of a static or member method, returns its kind.
2581d169d70bSTobias Grosser  */
2582d169d70bSTobias Grosser cpp_generator::function_kind cpp_generator::get_method_kind(
2583d169d70bSTobias Grosser 	const isl_class &clazz, FunctionDecl *method)
2584d169d70bSTobias Grosser {
2585d169d70bSTobias Grosser 	if (is_static(clazz, method))
2586d169d70bSTobias Grosser 		return function_kind_static_method;
2587d169d70bSTobias Grosser 	else
2588d169d70bSTobias Grosser 		return function_kind_member_method;
2589d169d70bSTobias Grosser }
2590