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