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