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 
2926145b11cSTobias 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)
3806145b11cSTobias Grosser 		print_method_group_decl(os, clazz, it->second);
381d169d70bSTobias Grosser }
382d169d70bSTobias Grosser 
3836145b11cSTobias 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,
3866145b11cSTobias 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);
3926145b11cSTobias 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,
4016145b11cSTobias Grosser 	FunctionDecl *method, function_kind kind)
402d169d70bSTobias Grosser {
4036145b11cSTobias 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 
451*26269d34STobias Grosser /* Print code that checks that "ptr" is not NULL at input.
452*26269d34STobias Grosser  *
453*26269d34STobias Grosser  * Omit the check if checked C++ bindings are being generated.
454*26269d34STobias Grosser  */
455*26269d34STobias Grosser void cpp_generator::print_check_ptr(ostream &os, const char *ptr)
456*26269d34STobias Grosser {
457*26269d34STobias Grosser 	if (checked)
458*26269d34STobias Grosser 		return;
459*26269d34STobias Grosser 
460*26269d34STobias Grosser 	osprintf(os, "  if (!%s)\n", ptr);
461*26269d34STobias Grosser 	print_throw_NULL_input(os);
462*26269d34STobias Grosser }
463*26269d34STobias Grosser 
464*26269d34STobias Grosser /* Print code that checks that "ptr" is not NULL at input and
465*26269d34STobias Grosser  * that saves a copy of the isl_ctx of "ptr" for a later check.
466*26269d34STobias Grosser  *
467*26269d34STobias Grosser  * Omit the check if checked C++ bindings are being generated.
468*26269d34STobias Grosser  */
469*26269d34STobias Grosser void cpp_generator::print_check_ptr_start(ostream &os, const isl_class &clazz,
470*26269d34STobias Grosser 	const char *ptr)
471*26269d34STobias Grosser {
472*26269d34STobias Grosser 	if (checked)
473*26269d34STobias Grosser 		return;
474*26269d34STobias Grosser 
475*26269d34STobias Grosser 	print_check_ptr(os, ptr);
476*26269d34STobias Grosser 	osprintf(os, "  auto ctx = %s_get_ctx(%s);\n", clazz.name.c_str(), ptr);
477*26269d34STobias Grosser 	print_on_error_continue(os);
478*26269d34STobias Grosser }
479*26269d34STobias Grosser 
480*26269d34STobias Grosser /* Print code that checks that "ptr" is not NULL at the end.
481*26269d34STobias Grosser  * A copy of the isl_ctx is expected to have been saved by
482*26269d34STobias Grosser  * code generated by print_check_ptr_start.
483*26269d34STobias Grosser  *
484*26269d34STobias Grosser  * Omit the check if checked C++ bindings are being generated.
485*26269d34STobias Grosser  */
486*26269d34STobias Grosser void cpp_generator::print_check_ptr_end(ostream &os, const char *ptr)
487*26269d34STobias Grosser {
488*26269d34STobias Grosser 	if (checked)
489*26269d34STobias Grosser 		return;
490*26269d34STobias Grosser 
491*26269d34STobias Grosser 	osprintf(os, "  if (!%s)\n", ptr);
492*26269d34STobias Grosser 	print_throw_last_error(os);
493*26269d34STobias Grosser }
494*26269d34STobias Grosser 
495d169d70bSTobias Grosser /* Print implementation of global factory functions to "os".
496d169d70bSTobias Grosser  *
497d169d70bSTobias Grosser  * Each class has two global factory functions:
498d169d70bSTobias Grosser  *
499d169d70bSTobias Grosser  * 	set manage(__isl_take isl_set *ptr);
500d169d70bSTobias Grosser  * 	set manage_copy(__isl_keep isl_set *ptr);
501d169d70bSTobias Grosser  *
502d169d70bSTobias Grosser  * Unless checked C++ bindings are being generated,
503d169d70bSTobias Grosser  * both functions require the argument to be non-NULL.
504d169d70bSTobias Grosser  * An exception is thrown if anything went wrong during the copying
505d169d70bSTobias Grosser  * in manage_copy.
506d169d70bSTobias Grosser  * During the copying, isl is made not to print any error message
507d169d70bSTobias Grosser  * because the error message is included in the exception.
508d169d70bSTobias Grosser  */
509d169d70bSTobias Grosser void cpp_generator::print_class_factory_impl(ostream &os,
510d169d70bSTobias Grosser 	const isl_class &clazz)
511d169d70bSTobias Grosser {
512d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
513d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
514d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
515d169d70bSTobias Grosser 
516d169d70bSTobias Grosser 	osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
517*26269d34STobias Grosser 	print_check_ptr(os, "ptr");
518d169d70bSTobias Grosser 	osprintf(os, "  return %s(ptr);\n", cppname);
519d169d70bSTobias Grosser 	osprintf(os, "}\n");
520d169d70bSTobias Grosser 
521d169d70bSTobias Grosser 	osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
522d169d70bSTobias Grosser 		name);
523*26269d34STobias Grosser 	print_check_ptr_start(os, clazz, "ptr");
524d169d70bSTobias Grosser 	osprintf(os, "  ptr = %s_copy(ptr);\n", name);
525*26269d34STobias Grosser 	print_check_ptr_end(os, "ptr");
526d169d70bSTobias Grosser 	osprintf(os, "  return %s(ptr);\n", cppname);
527d169d70bSTobias Grosser 	osprintf(os, "}\n");
528d169d70bSTobias Grosser }
529d169d70bSTobias Grosser 
530d169d70bSTobias Grosser /* Print implementations of private constructors for class "clazz" to "os".
531d169d70bSTobias Grosser  */
532d169d70bSTobias Grosser void cpp_generator::print_private_constructors_impl(ostream &os,
533d169d70bSTobias Grosser 	const isl_class &clazz)
534d169d70bSTobias Grosser {
535d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
536d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
537d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
538d169d70bSTobias Grosser 
539d169d70bSTobias Grosser 	osprintf(os, "%s::%s(__isl_take %s *ptr)\n    : ptr(ptr) {}\n",
540d169d70bSTobias Grosser 		 cppname, cppname, name);
541d169d70bSTobias Grosser }
542d169d70bSTobias Grosser 
543d169d70bSTobias Grosser /* Print implementations of public constructors for class "clazz" to "os".
544d169d70bSTobias Grosser  *
545d169d70bSTobias Grosser  * Throw an exception from the copy constructor if anything went wrong
546d169d70bSTobias Grosser  * during the copying or if the input is NULL.
547d169d70bSTobias Grosser  * During the copying, isl is made not to print any error message
548d169d70bSTobias Grosser  * because the error message is included in the exception.
549d169d70bSTobias Grosser  * No exceptions are thrown if checked C++ bindings
550d169d70bSTobias Grosser  * are being generated,
551d169d70bSTobias Grosser  */
552d169d70bSTobias Grosser void cpp_generator::print_public_constructors_impl(ostream &os,
553d169d70bSTobias Grosser 	const isl_class &clazz)
554d169d70bSTobias Grosser {
555d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
556d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
557d169d70bSTobias Grosser 
558d169d70bSTobias Grosser 	osprintf(os, "%s::%s()\n    : ptr(nullptr) {}\n\n", cppname, cppname);
559d169d70bSTobias Grosser 	osprintf(os, "%s::%s(const %s &obj)\n    : ptr(nullptr)\n",
560d169d70bSTobias Grosser 		 cppname, cppname, cppname);
561d169d70bSTobias Grosser 	osprintf(os, "{\n");
562*26269d34STobias Grosser 	print_check_ptr_start(os, clazz, "obj.ptr");
563d169d70bSTobias Grosser 	osprintf(os, "  ptr = obj.copy();\n");
564*26269d34STobias Grosser 	print_check_ptr_end(os, "ptr");
565d169d70bSTobias Grosser 	osprintf(os, "}\n");
566d169d70bSTobias Grosser }
567d169d70bSTobias Grosser 
568d169d70bSTobias Grosser /* Print implementations of constructors for class "clazz" to "os".
569d169d70bSTobias Grosser  */
570d169d70bSTobias Grosser void cpp_generator::print_constructors_impl(ostream &os,
571d169d70bSTobias Grosser        const isl_class &clazz)
572d169d70bSTobias Grosser {
573d169d70bSTobias Grosser 	set<FunctionDecl *>::const_iterator in;
574d169d70bSTobias Grosser 	const set<FunctionDecl *> constructors = clazz.constructors;
575d169d70bSTobias Grosser 
576d169d70bSTobias Grosser 	for (in = constructors.begin(); in != constructors.end(); ++in) {
577d169d70bSTobias Grosser 		FunctionDecl *cons = *in;
578d169d70bSTobias Grosser 
5796145b11cSTobias Grosser 		print_method_impl(os, clazz, cons, function_kind_constructor);
580d169d70bSTobias Grosser 	}
581d169d70bSTobias Grosser }
582d169d70bSTobias Grosser 
583d169d70bSTobias Grosser /* Print implementation of copy assignment operator for class "clazz" to "os".
584d169d70bSTobias Grosser  */
585d169d70bSTobias Grosser void cpp_generator::print_copy_assignment_impl(ostream &os,
586d169d70bSTobias Grosser 	const isl_class &clazz)
587d169d70bSTobias Grosser {
588d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
589d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
590d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
591d169d70bSTobias Grosser 
592d169d70bSTobias Grosser 	osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname,
593d169d70bSTobias Grosser 		 cppname, cppname);
594d169d70bSTobias Grosser 	osprintf(os, "  std::swap(this->ptr, obj.ptr);\n", name);
595d169d70bSTobias Grosser 	osprintf(os, "  return *this;\n");
596d169d70bSTobias Grosser 	osprintf(os, "}\n");
597d169d70bSTobias Grosser }
598d169d70bSTobias Grosser 
599d169d70bSTobias Grosser /* Print implementation of destructor for class "clazz" to "os".
600d169d70bSTobias Grosser  */
601d169d70bSTobias Grosser void cpp_generator::print_destructor_impl(ostream &os,
602d169d70bSTobias Grosser 	const isl_class &clazz)
603d169d70bSTobias Grosser {
604d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
605d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
606d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
607d169d70bSTobias Grosser 
608d169d70bSTobias Grosser 	osprintf(os, "%s::~%s() {\n", cppname, cppname);
609d169d70bSTobias Grosser 	osprintf(os, "  if (ptr)\n");
610d169d70bSTobias Grosser 	osprintf(os, "    %s_free(ptr);\n", name);
611d169d70bSTobias Grosser 	osprintf(os, "}\n");
612d169d70bSTobias Grosser }
613d169d70bSTobias Grosser 
614d169d70bSTobias Grosser /* Print implementation of ptr() functions for class "clazz" to "os".
615d169d70bSTobias Grosser  */
616d169d70bSTobias Grosser void cpp_generator::print_ptr_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, "__isl_give %s *%s::copy() const & {\n", name, cppname);
623d169d70bSTobias Grosser 	osprintf(os, "  return %s_copy(ptr);\n", name);
624d169d70bSTobias Grosser 	osprintf(os, "}\n\n");
625d169d70bSTobias Grosser 	osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
626d169d70bSTobias Grosser 	osprintf(os, "  return ptr;\n");
627d169d70bSTobias Grosser 	osprintf(os, "}\n\n");
628d169d70bSTobias Grosser 	osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
629d169d70bSTobias Grosser 	osprintf(os, "  %s *tmp = ptr;\n", name);
630d169d70bSTobias Grosser 	osprintf(os, "  ptr = nullptr;\n");
631d169d70bSTobias Grosser 	osprintf(os, "  return tmp;\n");
632d169d70bSTobias Grosser 	osprintf(os, "}\n\n");
633d169d70bSTobias Grosser 	osprintf(os, "bool %s::is_null() const {\n", cppname);
634d169d70bSTobias Grosser 	osprintf(os, "  return ptr == nullptr;\n");
635d169d70bSTobias Grosser 	osprintf(os, "}\n");
636d169d70bSTobias Grosser }
637d169d70bSTobias Grosser 
638d169d70bSTobias Grosser /* Print the implementation of the get_ctx method.
639d169d70bSTobias Grosser  */
640d169d70bSTobias Grosser void cpp_generator::print_get_ctx_impl(ostream &os, const isl_class &clazz)
641d169d70bSTobias Grosser {
642d169d70bSTobias Grosser 	const char *name = clazz.name.c_str();
643d169d70bSTobias Grosser 	std::string cppstring = type2cpp(clazz);
644d169d70bSTobias Grosser 	const char *cppname = cppstring.c_str();
645d169d70bSTobias Grosser 
646d169d70bSTobias Grosser 	osprintf(os, "ctx %s::get_ctx() const {\n", cppname);
647d169d70bSTobias Grosser 	osprintf(os, "  return ctx(%s_get_ctx(ptr));\n", name);
648d169d70bSTobias Grosser 	osprintf(os, "}\n");
649d169d70bSTobias Grosser }
650d169d70bSTobias Grosser 
651d169d70bSTobias Grosser /* Print definitions for methods of class "clazz" to "os".
652d169d70bSTobias Grosser  */
653d169d70bSTobias Grosser void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz)
654d169d70bSTobias Grosser {
655d169d70bSTobias Grosser 	map<string, set<FunctionDecl *> >::const_iterator it;
656d169d70bSTobias Grosser 	bool first = true;
657d169d70bSTobias Grosser 
658d169d70bSTobias Grosser 	for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) {
659d169d70bSTobias Grosser 		if (first)
660d169d70bSTobias Grosser 			first = false;
661d169d70bSTobias Grosser 		else
662d169d70bSTobias Grosser 			osprintf(os, "\n");
6636145b11cSTobias Grosser 		print_method_group_impl(os, clazz, it->second);
664d169d70bSTobias Grosser 	}
665d169d70bSTobias Grosser }
666d169d70bSTobias Grosser 
6676145b11cSTobias Grosser /* Print definitions for methods "methods" in class "clazz" to "os".
668d169d70bSTobias Grosser  *
669d169d70bSTobias Grosser  * "kind" specifies the kind of method that should be generated.
670d169d70bSTobias Grosser  */
671d169d70bSTobias Grosser void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz,
6726145b11cSTobias Grosser 	const set<FunctionDecl *> &methods)
673d169d70bSTobias Grosser {
674d169d70bSTobias Grosser 	set<FunctionDecl *>::const_iterator it;
675d169d70bSTobias Grosser 	bool first = true;
676d169d70bSTobias Grosser 
677d169d70bSTobias Grosser 	for (it = methods.begin(); it != methods.end(); ++it) {
678d169d70bSTobias Grosser 		function_kind kind;
679d169d70bSTobias Grosser 		if (first)
680d169d70bSTobias Grosser 			first = false;
681d169d70bSTobias Grosser 		else
682d169d70bSTobias Grosser 			osprintf(os, "\n");
683d169d70bSTobias Grosser 		kind = get_method_kind(clazz, *it);
6846145b11cSTobias Grosser 		print_method_impl(os, clazz, *it, kind);
685d169d70bSTobias Grosser 	}
686d169d70bSTobias Grosser }
687d169d70bSTobias Grosser 
688d169d70bSTobias Grosser /* Print the use of "param" to "os".
689d169d70bSTobias Grosser  *
690d169d70bSTobias Grosser  * "load_from_this_ptr" specifies whether the parameter should be loaded from
691d169d70bSTobias Grosser  * the this-ptr.  In case a value is loaded from a this pointer, the original
692d169d70bSTobias Grosser  * value must be preserved and must consequently be copied.  Values that are
693d169d70bSTobias Grosser  * loaded from parameters do not need to be preserved, as such values will
694d169d70bSTobias Grosser  * already be copies of the actual parameters.  It is consequently possible
695d169d70bSTobias Grosser  * to directly take the pointer from these values, which saves
696d169d70bSTobias Grosser  * an unnecessary copy.
697d169d70bSTobias Grosser  *
698d169d70bSTobias Grosser  * In case the parameter is a callback function, two parameters get printed,
699d169d70bSTobias Grosser  * a wrapper for the callback function and a pointer to the actual
700d169d70bSTobias Grosser  * callback function.  The wrapper is expected to be available
701d169d70bSTobias Grosser  * in a previously declared variable <name>_lambda, while
702d169d70bSTobias Grosser  * the actual callback function is expected to be stored
703d169d70bSTobias Grosser  * in a structure called <name>_data.
704d169d70bSTobias Grosser  * The caller of this function must ensure that these variables exist.
705d169d70bSTobias Grosser  */
706d169d70bSTobias Grosser void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param,
707d169d70bSTobias Grosser 	bool load_from_this_ptr)
708d169d70bSTobias Grosser {
709d169d70bSTobias Grosser 	string name = param->getName().str();
710d169d70bSTobias Grosser 	const char *name_str = name.c_str();
711d169d70bSTobias Grosser 	QualType type = param->getOriginalType();
712d169d70bSTobias Grosser 
713d169d70bSTobias Grosser 	if (type->isIntegerType()) {
714d169d70bSTobias Grosser 		osprintf(os, "%s", name_str);
715d169d70bSTobias Grosser 		return;
716d169d70bSTobias Grosser 	}
717d169d70bSTobias Grosser 
718d169d70bSTobias Grosser 	if (is_string(type)) {
719d169d70bSTobias Grosser 		osprintf(os, "%s.c_str()", name_str);
720d169d70bSTobias Grosser 		return;
721d169d70bSTobias Grosser 	}
722d169d70bSTobias Grosser 
723d169d70bSTobias Grosser 	if (is_callback(type)) {
724d169d70bSTobias Grosser 		osprintf(os, "%s_lambda, ", name_str);
725d169d70bSTobias Grosser 		osprintf(os, "&%s_data", name_str);
726d169d70bSTobias Grosser 		return;
727d169d70bSTobias Grosser 	}
728d169d70bSTobias Grosser 
729d169d70bSTobias Grosser 	if (!load_from_this_ptr && !is_callback(type))
730d169d70bSTobias Grosser 		osprintf(os, "%s.", name_str);
731d169d70bSTobias Grosser 
732d169d70bSTobias Grosser 	if (keeps(param)) {
733d169d70bSTobias Grosser 		osprintf(os, "get()");
734d169d70bSTobias Grosser 	} else {
735d169d70bSTobias Grosser 		if (load_from_this_ptr)
736d169d70bSTobias Grosser 			osprintf(os, "copy()");
737d169d70bSTobias Grosser 		else
738d169d70bSTobias Grosser 			osprintf(os, "release()");
739d169d70bSTobias Grosser 	}
740d169d70bSTobias Grosser }
741d169d70bSTobias Grosser 
742d169d70bSTobias Grosser /* Print code that checks that all isl object arguments to "method" are valid
743d169d70bSTobias Grosser  * (not NULL) and throws an exception if they are not.
744d169d70bSTobias Grosser  * "kind" specifies the kind of method that is being generated.
745d169d70bSTobias Grosser  *
746d169d70bSTobias Grosser  * If checked bindings are being generated,
747d169d70bSTobias Grosser  * then no such check is performed.
748d169d70bSTobias Grosser  */
749d169d70bSTobias Grosser void cpp_generator::print_argument_validity_check(ostream &os,
750d169d70bSTobias Grosser 	FunctionDecl *method, function_kind kind)
751d169d70bSTobias Grosser {
752d169d70bSTobias Grosser 	int n;
753d169d70bSTobias Grosser 	bool first = true;
754d169d70bSTobias Grosser 
755d169d70bSTobias Grosser 	if (checked)
756d169d70bSTobias Grosser 		return;
757d169d70bSTobias Grosser 
758d169d70bSTobias Grosser 	n = method->getNumParams();
759d169d70bSTobias Grosser 	for (int i = 0; i < n; ++i) {
760d169d70bSTobias Grosser 		bool is_this;
761d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
762d169d70bSTobias Grosser 		string name = param->getName().str();
763d169d70bSTobias Grosser 		const char *name_str = name.c_str();
764d169d70bSTobias Grosser 		QualType type = param->getOriginalType();
765d169d70bSTobias Grosser 
766d169d70bSTobias Grosser 		is_this = i == 0 && kind == function_kind_member_method;
767d169d70bSTobias Grosser 		if (!is_this && (is_isl_ctx(type) || !is_isl_type(type)))
768d169d70bSTobias Grosser 			continue;
769d169d70bSTobias Grosser 
770d169d70bSTobias Grosser 		if (first)
771d169d70bSTobias Grosser 			osprintf(os, "  if (");
772d169d70bSTobias Grosser 		else
773d169d70bSTobias Grosser 			osprintf(os, " || ");
774d169d70bSTobias Grosser 
775d169d70bSTobias Grosser 		if (is_this)
776d169d70bSTobias Grosser 			osprintf(os, "!ptr");
777d169d70bSTobias Grosser 		else
778d169d70bSTobias Grosser 			osprintf(os, "%s.is_null()", name_str);
779d169d70bSTobias Grosser 
780d169d70bSTobias Grosser 		first = false;
781d169d70bSTobias Grosser 	}
782d169d70bSTobias Grosser 	if (first)
783d169d70bSTobias Grosser 		return;
784d169d70bSTobias Grosser 	osprintf(os, ")\n");
785d169d70bSTobias Grosser 	print_throw_NULL_input(os);
786d169d70bSTobias Grosser }
787d169d70bSTobias Grosser 
788d169d70bSTobias Grosser /* Print code for saving a copy of the isl::ctx available at the start
789d169d70bSTobias Grosser  * of the method "method" in a "ctx" variable, for use in exception handling.
790d169d70bSTobias Grosser  * "kind" specifies what kind of method "method" is.
791d169d70bSTobias Grosser  *
792d169d70bSTobias Grosser  * If checked bindings are being generated,
793d169d70bSTobias Grosser  * then the "ctx" variable is not needed.
794d169d70bSTobias Grosser  * If "method" is a member function, then obtain the isl_ctx from
795d169d70bSTobias Grosser  * the "this" object.
796d169d70bSTobias Grosser  * If the first argument of the method is an isl::ctx, then use that one,
797d169d70bSTobias Grosser  * assuming it is not already called "ctx".
798d169d70bSTobias Grosser  * Otherwise, save a copy of the isl::ctx associated to the first argument
799d169d70bSTobias Grosser  * of isl object type.
800d169d70bSTobias Grosser  */
801d169d70bSTobias Grosser void cpp_generator::print_save_ctx(ostream &os, FunctionDecl *method,
802d169d70bSTobias Grosser 	function_kind kind)
803d169d70bSTobias Grosser {
804d169d70bSTobias Grosser 	int n;
805d169d70bSTobias Grosser 	ParmVarDecl *param = method->getParamDecl(0);
806d169d70bSTobias Grosser 	QualType type = param->getOriginalType();
807d169d70bSTobias Grosser 
808d169d70bSTobias Grosser 	if (checked)
809d169d70bSTobias Grosser 		return;
810d169d70bSTobias Grosser 	if (kind == function_kind_member_method) {
811d169d70bSTobias Grosser 		osprintf(os, "  auto ctx = get_ctx();\n");
812d169d70bSTobias Grosser 		return;
813d169d70bSTobias Grosser 	}
814d169d70bSTobias Grosser 	if (is_isl_ctx(type)) {
815d169d70bSTobias Grosser 		const char *name;
816d169d70bSTobias Grosser 
817d169d70bSTobias Grosser 		name = param->getName().str().c_str();
818d169d70bSTobias Grosser 		if (strcmp(name, "ctx") != 0)
819d169d70bSTobias Grosser 			osprintf(os, "  auto ctx = %s;\n", name);
820d169d70bSTobias Grosser 		return;
821d169d70bSTobias Grosser 	}
822d169d70bSTobias Grosser 	n = method->getNumParams();
823d169d70bSTobias Grosser 	for (int i = 0; i < n; ++i) {
824d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
825d169d70bSTobias Grosser 		QualType type = param->getOriginalType();
826d169d70bSTobias Grosser 
827d169d70bSTobias Grosser 		if (!is_isl_type(type))
828d169d70bSTobias Grosser 			continue;
829d169d70bSTobias Grosser 		osprintf(os, "  auto ctx = %s.get_ctx();\n",
830d169d70bSTobias Grosser 			param->getName().str().c_str());
831d169d70bSTobias Grosser 		return;
832d169d70bSTobias Grosser 	}
833d169d70bSTobias Grosser }
834d169d70bSTobias Grosser 
835d169d70bSTobias Grosser /* Print code to make isl not print an error message when an error occurs
836d169d70bSTobias Grosser  * within the current scope (if exceptions are available),
837d169d70bSTobias Grosser  * since the error message will be included in the exception.
838d169d70bSTobias Grosser  * If exceptions are not available, then exception::on_error
839d169d70bSTobias Grosser  * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead.
840d169d70bSTobias Grosser  *
841d169d70bSTobias Grosser  * If checked bindings are being generated,
842d169d70bSTobias Grosser  * then leave it to the user to decide what isl should do on error.
843d169d70bSTobias Grosser  * Otherwise, assume that a valid isl::ctx is available in the "ctx" variable,
844d169d70bSTobias Grosser  * e.g., through a prior call to print_save_ctx.
845d169d70bSTobias Grosser  */
846d169d70bSTobias Grosser void cpp_generator::print_on_error_continue(ostream &os)
847d169d70bSTobias Grosser {
848d169d70bSTobias Grosser 	if (checked)
849d169d70bSTobias Grosser 		return;
850d169d70bSTobias Grosser 	osprintf(os, "  options_scoped_set_on_error saved_on_error(ctx, "
851d169d70bSTobias Grosser 		     "exception::on_error);\n");
852d169d70bSTobias Grosser }
853d169d70bSTobias Grosser 
854d169d70bSTobias Grosser /* Print code that checks whether the execution of the core of "method"
855d169d70bSTobias Grosser  * was successful.
856d169d70bSTobias Grosser  *
857d169d70bSTobias Grosser  * If checked bindings are being generated,
858d169d70bSTobias Grosser  * then no checks are performed.
859d169d70bSTobias Grosser  *
860d169d70bSTobias Grosser  * Otherwise, first check if any of the callbacks failed with
861d169d70bSTobias Grosser  * an exception.  If so, the "eptr" in the corresponding data structure
862d169d70bSTobias Grosser  * contains the exception that was caught and that needs to be rethrown.
863d169d70bSTobias Grosser  * Then check if the function call failed in any other way and throw
864d169d70bSTobias Grosser  * the appropriate exception.
865d169d70bSTobias Grosser  * In particular, if the return type is isl_stat or isl_bool,
866d169d70bSTobias Grosser  * then a negative value indicates a failure.  If the return type
867d169d70bSTobias Grosser  * is an isl type, then a NULL value indicates a failure.
868d169d70bSTobias Grosser  * Assume print_save_ctx has made sure that a valid isl::ctx
869d169d70bSTobias Grosser  * is available in the "ctx" variable.
870d169d70bSTobias Grosser  */
871d169d70bSTobias Grosser void cpp_generator::print_exceptional_execution_check(ostream &os,
872d169d70bSTobias Grosser 	FunctionDecl *method)
873d169d70bSTobias Grosser {
874d169d70bSTobias Grosser 	int n;
875d169d70bSTobias Grosser 	bool check_null, check_neg;
876d169d70bSTobias Grosser 	QualType return_type = method->getReturnType();
877d169d70bSTobias Grosser 
878d169d70bSTobias Grosser 	if (checked)
879d169d70bSTobias Grosser 		return;
880d169d70bSTobias Grosser 
881d169d70bSTobias Grosser 	n = method->getNumParams();
882d169d70bSTobias Grosser 	for (int i = 0; i < n; ++i) {
883d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
884d169d70bSTobias Grosser 		const char *name;
885d169d70bSTobias Grosser 
886d169d70bSTobias Grosser 		if (!is_callback(param->getOriginalType()))
887d169d70bSTobias Grosser 			continue;
888d169d70bSTobias Grosser 		name = param->getName().str().c_str();
889d169d70bSTobias Grosser 		osprintf(os, "  if (%s_data.eptr)\n", name);
890d169d70bSTobias Grosser 		osprintf(os, "    std::rethrow_exception(%s_data.eptr);\n",
891d169d70bSTobias Grosser 			name);
892d169d70bSTobias Grosser 	}
893d169d70bSTobias Grosser 
894d169d70bSTobias Grosser 	check_neg = is_isl_stat(return_type) || is_isl_bool(return_type);
895d169d70bSTobias Grosser 	check_null = is_isl_type(return_type);
896d169d70bSTobias Grosser 	if (!check_null && !check_neg)
897d169d70bSTobias Grosser 		return;
898d169d70bSTobias Grosser 
899d169d70bSTobias Grosser 	if (check_neg)
900d169d70bSTobias Grosser 		osprintf(os, "  if (res < 0)\n");
901d169d70bSTobias Grosser 	else
902d169d70bSTobias Grosser 		osprintf(os, "  if (!res)\n");
903d169d70bSTobias Grosser 	print_throw_last_error(os);
904d169d70bSTobias Grosser }
905d169d70bSTobias Grosser 
906*26269d34STobias Grosser /* Print the return statement of the C++ method corresponding
907*26269d34STobias Grosser  * to the C function "method" in class "clazz" to "os".
908d169d70bSTobias Grosser  *
909*26269d34STobias Grosser  * The result of the isl function is returned as a new
910d169d70bSTobias Grosser  * object if the underlying isl function returns an isl_* ptr, as a bool
911d169d70bSTobias Grosser  * if the isl function returns an isl_bool, as void if the isl functions
912d169d70bSTobias Grosser  * returns an isl_stat,
913d169d70bSTobias Grosser  * as std::string if the isl function returns 'const char *', and as
914d169d70bSTobias Grosser  * unmodified return value otherwise.
915d169d70bSTobias Grosser  * If checked C++ bindings are being generated,
916d169d70bSTobias Grosser  * then an isl_bool return type is transformed into a boolean and
917d169d70bSTobias Grosser  * an isl_stat into a stat since no exceptions can be generated
918d169d70bSTobias Grosser  * on negative results from the isl function.
919*26269d34STobias Grosser  */
920*26269d34STobias Grosser void cpp_generator::print_method_return(ostream &os, const isl_class &clazz,
921*26269d34STobias Grosser 	FunctionDecl *method)
922*26269d34STobias Grosser {
923*26269d34STobias Grosser 	QualType return_type = method->getReturnType();
924*26269d34STobias Grosser 
925*26269d34STobias Grosser 	if (is_isl_type(return_type) ||
926*26269d34STobias Grosser 		    (checked &&
927*26269d34STobias Grosser 		     (is_isl_bool(return_type) || is_isl_stat(return_type)))) {
928*26269d34STobias Grosser 		osprintf(os, "  return manage(res);\n");
929*26269d34STobias Grosser 	} else if (is_isl_stat(return_type)) {
930*26269d34STobias Grosser 		osprintf(os, "  return;\n");
931*26269d34STobias Grosser 	} else if (is_string(return_type)) {
932*26269d34STobias Grosser 		osprintf(os, "  std::string tmp(res);\n");
933*26269d34STobias Grosser 		if (gives(method))
934*26269d34STobias Grosser 			osprintf(os, "  free(res);\n");
935*26269d34STobias Grosser 		osprintf(os, "  return tmp;\n");
936*26269d34STobias Grosser 	} else {
937*26269d34STobias Grosser 		osprintf(os, "  return res;\n");
938*26269d34STobias Grosser 	}
939*26269d34STobias Grosser }
940*26269d34STobias Grosser 
941*26269d34STobias Grosser /* Print definition for "method" in class "clazz" to "os".
942*26269d34STobias Grosser  *
943*26269d34STobias Grosser  * "kind" specifies the kind of method that should be generated.
944*26269d34STobias Grosser  *
945*26269d34STobias Grosser  * This method distinguishes three kinds of methods: member methods, static
946*26269d34STobias Grosser  * methods, and constructors.
947*26269d34STobias Grosser  *
948*26269d34STobias Grosser  * Member methods call "method" by passing to the underlying isl function the
949*26269d34STobias Grosser  * isl object belonging to "this" as first argument and the remaining arguments
950*26269d34STobias Grosser  * as subsequent arguments.
951d169d70bSTobias Grosser  *
952d169d70bSTobias Grosser  * Static methods call "method" by passing all arguments to the underlying isl
953d169d70bSTobias Grosser  * function, as no this-pointer is available. The result is a newly managed
954d169d70bSTobias Grosser  * isl C++ object.
955d169d70bSTobias Grosser  *
956d169d70bSTobias Grosser  * Constructors create a new object from a given set of input parameters. They
957d169d70bSTobias Grosser  * do not return a value, but instead update the pointer stored inside the
958d169d70bSTobias Grosser  * newly created object.
959d169d70bSTobias Grosser  *
960d169d70bSTobias Grosser  * If the method has a callback argument, we reduce the number of parameters
961d169d70bSTobias Grosser  * that are exposed by one to hide the user pointer from the interface. On
962d169d70bSTobias Grosser  * the C++ side no user pointer is needed, as arguments can be forwarded
963d169d70bSTobias Grosser  * as part of the std::function argument which specifies the callback function.
964d169d70bSTobias Grosser  *
965d169d70bSTobias Grosser  * Unless checked C++ bindings are being generated,
966d169d70bSTobias Grosser  * the inputs of the method are first checked for being valid isl objects and
967d169d70bSTobias Grosser  * a copy of the associated isl::ctx is saved (if needed).
968d169d70bSTobias Grosser  * If any failure occurs, either during the check for the inputs or
969d169d70bSTobias Grosser  * during the isl function call, an exception is thrown.
970d169d70bSTobias Grosser  * During the function call, isl is made not to print any error message
971d169d70bSTobias Grosser  * because the error message is included in the exception.
972d169d70bSTobias Grosser  */
973d169d70bSTobias Grosser void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz,
9746145b11cSTobias Grosser 	FunctionDecl *method, function_kind kind)
975d169d70bSTobias Grosser {
976d169d70bSTobias Grosser 	string methodname = method->getName();
977d169d70bSTobias Grosser 	int num_params = method->getNumParams();
978d169d70bSTobias Grosser 
9796145b11cSTobias Grosser 	print_method_header(os, clazz, method, false, kind);
980d169d70bSTobias Grosser 	osprintf(os, "{\n");
981d169d70bSTobias Grosser 	print_argument_validity_check(os, method, kind);
982d169d70bSTobias Grosser 	print_save_ctx(os, method, kind);
983d169d70bSTobias Grosser 	print_on_error_continue(os);
984d169d70bSTobias Grosser 
985d169d70bSTobias Grosser 	for (int i = 0; i < num_params; ++i) {
986d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
987d169d70bSTobias Grosser 		if (is_callback(param->getType())) {
988d169d70bSTobias Grosser 			num_params -= 1;
989d169d70bSTobias Grosser 			print_callback_local(os, param);
990d169d70bSTobias Grosser 		}
991d169d70bSTobias Grosser 	}
992d169d70bSTobias Grosser 
993d169d70bSTobias Grosser 	osprintf(os, "  auto res = %s(", methodname.c_str());
994d169d70bSTobias Grosser 
995d169d70bSTobias Grosser 	for (int i = 0; i < num_params; ++i) {
996d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
997d169d70bSTobias Grosser 		bool load_from_this_ptr = false;
998d169d70bSTobias Grosser 
999d169d70bSTobias Grosser 		if (i == 0 && kind == function_kind_member_method)
1000d169d70bSTobias Grosser 			load_from_this_ptr = true;
1001d169d70bSTobias Grosser 
1002d169d70bSTobias Grosser 		print_method_param_use(os, param, load_from_this_ptr);
1003d169d70bSTobias Grosser 
1004d169d70bSTobias Grosser 		if (i != num_params - 1)
1005d169d70bSTobias Grosser 			osprintf(os, ", ");
1006d169d70bSTobias Grosser 	}
1007d169d70bSTobias Grosser 	osprintf(os, ");\n");
1008d169d70bSTobias Grosser 
1009d169d70bSTobias Grosser 	print_exceptional_execution_check(os, method);
1010d169d70bSTobias Grosser 	if (kind == function_kind_constructor) {
1011d169d70bSTobias Grosser 		osprintf(os, "  ptr = res;\n");
1012d169d70bSTobias Grosser 	} else {
1013*26269d34STobias Grosser 		print_method_return(os, clazz, method);
1014d169d70bSTobias Grosser 	}
1015d169d70bSTobias Grosser 
1016d169d70bSTobias Grosser 	osprintf(os, "}\n");
1017d169d70bSTobias Grosser }
1018d169d70bSTobias Grosser 
1019d169d70bSTobias Grosser /* Print the header for "method" in class "clazz" to "os".
1020d169d70bSTobias Grosser  *
1021d169d70bSTobias Grosser  * Print the header of a declaration if "is_declaration" is set, otherwise print
1022d169d70bSTobias Grosser  * the header of a method definition.
1023d169d70bSTobias Grosser  *
1024d169d70bSTobias Grosser  * "kind" specifies the kind of method that should be generated.
1025d169d70bSTobias Grosser  *
1026d169d70bSTobias Grosser  * This function prints headers for member methods, static methods, and
1027d169d70bSTobias Grosser  * constructors, either for their declaration or definition.
1028d169d70bSTobias Grosser  *
1029d169d70bSTobias Grosser  * Member functions are declared as "const", as they do not change the current
1030d169d70bSTobias Grosser  * object, but instead create a new object. They always retrieve the first
1031d169d70bSTobias Grosser  * parameter of the original isl function from the this-pointer of the object,
1032d169d70bSTobias Grosser  * such that only starting at the second parameter the parameters of the
1033d169d70bSTobias Grosser  * original function become part of the method's interface.
1034d169d70bSTobias Grosser  *
1035d169d70bSTobias Grosser  * A function
1036d169d70bSTobias Grosser  *
1037d169d70bSTobias Grosser  * 	__isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
1038d169d70bSTobias Grosser  * 		__isl_take isl_set *s2);
1039d169d70bSTobias Grosser  *
1040d169d70bSTobias Grosser  * is translated into:
1041d169d70bSTobias Grosser  *
1042d169d70bSTobias Grosser  * 	inline set intersect(set set2) const;
1043d169d70bSTobias Grosser  *
1044d169d70bSTobias Grosser  * For static functions and constructors all parameters of the original isl
1045d169d70bSTobias Grosser  * function are exposed.
1046d169d70bSTobias Grosser  *
1047d169d70bSTobias Grosser  * Parameters that are defined as __isl_keep or are of type string, are passed
1048d169d70bSTobias Grosser  * as const reference, which allows the compiler to optimize the parameter
1049d169d70bSTobias Grosser  * transfer.
1050d169d70bSTobias Grosser  *
1051d169d70bSTobias Grosser  * Constructors are marked as explicit using the C++ keyword 'explicit' or as
1052d169d70bSTobias Grosser  * implicit using a comment in place of the explicit keyword. By annotating
1053d169d70bSTobias Grosser  * implicit constructors with a comment, users of the interface are made
1054d169d70bSTobias Grosser  * aware of the potential danger that implicit construction is possible
1055d169d70bSTobias Grosser  * for these constructors, whereas without a comment not every user would
1056d169d70bSTobias Grosser  * know that implicit construction is allowed in absence of an explicit keyword.
1057d169d70bSTobias Grosser  */
1058d169d70bSTobias Grosser void cpp_generator::print_method_header(ostream &os, const isl_class &clazz,
10596145b11cSTobias Grosser 	FunctionDecl *method, bool is_declaration, function_kind kind)
1060d169d70bSTobias Grosser {
10616145b11cSTobias Grosser 	string cname = clazz.method_name(method);
1062d169d70bSTobias Grosser 	string rettype_str = type2cpp(method->getReturnType());
1063d169d70bSTobias Grosser 	string classname = type2cpp(clazz);
1064d169d70bSTobias Grosser 	int num_params = method->getNumParams();
1065d169d70bSTobias Grosser 	int first_param = 0;
1066d169d70bSTobias Grosser 
1067d169d70bSTobias Grosser 	cname = rename_method(cname);
1068d169d70bSTobias Grosser 	if (kind == function_kind_member_method)
1069d169d70bSTobias Grosser 		first_param = 1;
1070d169d70bSTobias Grosser 
1071d169d70bSTobias Grosser 	if (is_declaration) {
1072d169d70bSTobias Grosser 		osprintf(os, "  ");
1073d169d70bSTobias Grosser 
1074d169d70bSTobias Grosser 		if (kind == function_kind_static_method)
1075d169d70bSTobias Grosser 			osprintf(os, "static ");
1076d169d70bSTobias Grosser 
1077d169d70bSTobias Grosser 		osprintf(os, "inline ");
1078d169d70bSTobias Grosser 
1079d169d70bSTobias Grosser 		if (kind == function_kind_constructor) {
1080d169d70bSTobias Grosser 			if (is_implicit_conversion(clazz, method))
1081d169d70bSTobias Grosser 				osprintf(os, "/* implicit */ ");
1082d169d70bSTobias Grosser 			else
1083d169d70bSTobias Grosser 				osprintf(os, "explicit ");
1084d169d70bSTobias Grosser 		}
1085d169d70bSTobias Grosser 	}
1086d169d70bSTobias Grosser 
1087d169d70bSTobias Grosser 	if (kind != function_kind_constructor)
1088d169d70bSTobias Grosser 		osprintf(os, "%s ", rettype_str.c_str());
1089d169d70bSTobias Grosser 
1090d169d70bSTobias Grosser 	if (!is_declaration)
1091d169d70bSTobias Grosser 		osprintf(os, "%s::", classname.c_str());
1092d169d70bSTobias Grosser 
1093d169d70bSTobias Grosser 	if (kind != function_kind_constructor)
1094d169d70bSTobias Grosser 		osprintf(os, "%s", cname.c_str());
1095d169d70bSTobias Grosser 	else
1096d169d70bSTobias Grosser 		osprintf(os, "%s", classname.c_str());
1097d169d70bSTobias Grosser 
1098d169d70bSTobias Grosser 	osprintf(os, "(");
1099d169d70bSTobias Grosser 
1100d169d70bSTobias Grosser 	for (int i = first_param; i < num_params; ++i) {
1101d169d70bSTobias Grosser 		ParmVarDecl *param = method->getParamDecl(i);
1102d169d70bSTobias Grosser 		QualType type = param->getOriginalType();
1103d169d70bSTobias Grosser 		string cpptype = type2cpp(type);
1104d169d70bSTobias Grosser 
1105d169d70bSTobias Grosser 		if (is_callback(type))
1106d169d70bSTobias Grosser 			num_params--;
1107d169d70bSTobias Grosser 
1108d169d70bSTobias Grosser 		if (keeps(param) || is_string(type) || is_callback(type))
1109d169d70bSTobias Grosser 			osprintf(os, "const %s &%s", cpptype.c_str(),
1110d169d70bSTobias Grosser 				 param->getName().str().c_str());
1111d169d70bSTobias Grosser 		else
1112d169d70bSTobias Grosser 			osprintf(os, "%s %s", cpptype.c_str(),
1113d169d70bSTobias Grosser 				 param->getName().str().c_str());
1114d169d70bSTobias Grosser 
1115d169d70bSTobias Grosser 		if (i != num_params - 1)
1116d169d70bSTobias Grosser 			osprintf(os, ", ");
1117d169d70bSTobias Grosser 	}
1118d169d70bSTobias Grosser 
1119d169d70bSTobias Grosser 	osprintf(os, ")");
1120d169d70bSTobias Grosser 
1121d169d70bSTobias Grosser 	if (kind == function_kind_member_method)
1122d169d70bSTobias Grosser 		osprintf(os, " const");
1123d169d70bSTobias Grosser 
1124d169d70bSTobias Grosser 	if (is_declaration)
1125d169d70bSTobias Grosser 		osprintf(os, ";");
1126d169d70bSTobias Grosser 	osprintf(os, "\n");
1127d169d70bSTobias Grosser }
1128d169d70bSTobias Grosser 
1129d169d70bSTobias Grosser /* Generate the list of argument types for a callback function of
1130d169d70bSTobias Grosser  * type "type".  If "cpp" is set, then generate the C++ type list, otherwise
1131d169d70bSTobias Grosser  * the C type list.
1132d169d70bSTobias Grosser  *
1133d169d70bSTobias Grosser  * For a callback of type
1134d169d70bSTobias Grosser  *
1135d169d70bSTobias Grosser  *      isl_stat (*)(__isl_take isl_map *map, void *user)
1136d169d70bSTobias Grosser  *
1137d169d70bSTobias Grosser  * the following C++ argument list is generated:
1138d169d70bSTobias Grosser  *
1139d169d70bSTobias Grosser  *      map
1140d169d70bSTobias Grosser  */
1141d169d70bSTobias Grosser string cpp_generator::generate_callback_args(QualType type, bool cpp)
1142d169d70bSTobias Grosser {
1143d169d70bSTobias Grosser 	std::string type_str;
1144d169d70bSTobias Grosser 	const FunctionProtoType *callback;
1145d169d70bSTobias Grosser 	int num_params;
1146d169d70bSTobias Grosser 
1147*26269d34STobias Grosser 	callback = extract_prototype(type);
1148d169d70bSTobias Grosser 	num_params = callback->getNumArgs();
1149d169d70bSTobias Grosser 	if (cpp)
1150d169d70bSTobias Grosser 		num_params--;
1151d169d70bSTobias Grosser 
1152d169d70bSTobias Grosser 	for (long i = 0; i < num_params; i++) {
1153d169d70bSTobias Grosser 		QualType type = callback->getArgType(i);
1154d169d70bSTobias Grosser 
1155d169d70bSTobias Grosser 		if (cpp)
1156d169d70bSTobias Grosser 			type_str += type2cpp(type);
1157d169d70bSTobias Grosser 		else
1158d169d70bSTobias Grosser 			type_str += type.getAsString();
1159d169d70bSTobias Grosser 
1160d169d70bSTobias Grosser 		if (!cpp)
1161d169d70bSTobias Grosser 			type_str += "arg_" + ::to_string(i);
1162d169d70bSTobias Grosser 
1163d169d70bSTobias Grosser 		if (i != num_params - 1)
1164d169d70bSTobias Grosser 			type_str += ", ";
1165d169d70bSTobias Grosser 	}
1166d169d70bSTobias Grosser 
1167d169d70bSTobias Grosser 	return type_str;
1168d169d70bSTobias Grosser }
1169d169d70bSTobias Grosser 
1170d169d70bSTobias Grosser /* Generate the full cpp type of a callback function of type "type".
1171d169d70bSTobias Grosser  *
1172d169d70bSTobias Grosser  * For a callback of type
1173d169d70bSTobias Grosser  *
1174d169d70bSTobias Grosser  *      isl_stat (*)(__isl_take isl_map *map, void *user)
1175d169d70bSTobias Grosser  *
1176d169d70bSTobias Grosser  * the following type is generated:
1177d169d70bSTobias Grosser  *
1178d169d70bSTobias Grosser  *      std::function<stat(map)>
1179d169d70bSTobias Grosser  */
1180d169d70bSTobias Grosser string cpp_generator::generate_callback_type(QualType type)
1181d169d70bSTobias Grosser {
1182d169d70bSTobias Grosser 	std::string type_str;
1183*26269d34STobias Grosser 	const FunctionProtoType *callback = extract_prototype(type);
1184d169d70bSTobias Grosser 	QualType return_type = callback->getReturnType();
1185d169d70bSTobias Grosser 	string rettype_str = type2cpp(return_type);
1186d169d70bSTobias Grosser 
1187d169d70bSTobias Grosser 	type_str = "std::function<";
1188d169d70bSTobias Grosser 	type_str += rettype_str;
1189d169d70bSTobias Grosser 	type_str += "(";
1190d169d70bSTobias Grosser 	type_str += generate_callback_args(type, true);
1191d169d70bSTobias Grosser 	type_str += ")>";
1192d169d70bSTobias Grosser 
1193d169d70bSTobias Grosser 	return type_str;
1194d169d70bSTobias Grosser }
1195d169d70bSTobias Grosser 
1196d169d70bSTobias Grosser /* Print the call to the C++ callback function "call", wrapped
1197d169d70bSTobias Grosser  * for use inside the lambda function that is used as the C callback function,
1198d169d70bSTobias Grosser  * in the case where checked C++ bindings are being generated.
1199d169d70bSTobias Grosser  *
1200d169d70bSTobias Grosser  * In particular, print
1201d169d70bSTobias Grosser  *
1202d169d70bSTobias Grosser  *        stat ret = @call@;
1203d169d70bSTobias Grosser  *        return ret.release();
1204d169d70bSTobias Grosser  */
1205d169d70bSTobias Grosser void cpp_generator::print_wrapped_call_checked(ostream &os,
1206d169d70bSTobias Grosser 	const string &call)
1207d169d70bSTobias Grosser {
1208d169d70bSTobias Grosser 	osprintf(os, "    stat ret = %s;\n", call.c_str());
1209d169d70bSTobias Grosser 	osprintf(os, "    return ret.release();\n");
1210d169d70bSTobias Grosser }
1211d169d70bSTobias Grosser 
1212d169d70bSTobias Grosser /* Print the call to the C++ callback function "call", wrapped
1213d169d70bSTobias Grosser  * for use inside the lambda function that is used as the C callback function.
1214d169d70bSTobias Grosser  *
1215d169d70bSTobias Grosser  * In particular, print
1216d169d70bSTobias Grosser  *
1217d169d70bSTobias Grosser  *        ISL_CPP_TRY {
1218d169d70bSTobias Grosser  *          @call@;
1219d169d70bSTobias Grosser  *          return isl_stat_ok;
1220d169d70bSTobias Grosser  *        } ISL_CPP_CATCH_ALL {
1221d169d70bSTobias Grosser  *          data->eptr = std::current_exception();
1222d169d70bSTobias Grosser  *          return isl_stat_error;
1223d169d70bSTobias Grosser  *        }
1224d169d70bSTobias Grosser  *
1225d169d70bSTobias Grosser  * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)"
1226d169d70bSTobias Grosser  * (if exceptions are available).
1227d169d70bSTobias Grosser  *
1228d169d70bSTobias Grosser  * If checked C++ bindings are being generated, then
1229d169d70bSTobias Grosser  * the call is wrapped differently.
1230d169d70bSTobias Grosser  */
1231d169d70bSTobias Grosser void cpp_generator::print_wrapped_call(ostream &os, const string &call)
1232d169d70bSTobias Grosser {
1233d169d70bSTobias Grosser 	if (checked)
1234d169d70bSTobias Grosser 		return print_wrapped_call_checked(os, call);
1235d169d70bSTobias Grosser 
1236d169d70bSTobias Grosser 	osprintf(os, "    ISL_CPP_TRY {\n");
1237d169d70bSTobias Grosser 	osprintf(os, "      %s;\n", call.c_str());
1238d169d70bSTobias Grosser 	osprintf(os, "      return isl_stat_ok;\n");
1239d169d70bSTobias Grosser 	osprintf(os, "    } ISL_CPP_CATCH_ALL {\n"
1240d169d70bSTobias Grosser 		     "      data->eptr = std::current_exception();\n");
1241d169d70bSTobias Grosser 	osprintf(os, "      return isl_stat_error;\n");
1242d169d70bSTobias Grosser 	osprintf(os, "    }\n");
1243d169d70bSTobias Grosser }
1244d169d70bSTobias Grosser 
1245d169d70bSTobias Grosser /* Print the local variables that are needed for a callback argument,
1246d169d70bSTobias Grosser  * in particular, print a lambda function that wraps the callback and
1247d169d70bSTobias Grosser  * a pointer to the actual C++ callback function.
1248d169d70bSTobias Grosser  *
1249d169d70bSTobias Grosser  * For a callback of the form
1250d169d70bSTobias Grosser  *
1251d169d70bSTobias Grosser  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
1252d169d70bSTobias Grosser  *
1253d169d70bSTobias Grosser  * the following lambda function is generated:
1254d169d70bSTobias Grosser  *
1255d169d70bSTobias Grosser  *      auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
1256d169d70bSTobias Grosser  *        auto *data = static_cast<struct fn_data *>(arg_1);
1257d169d70bSTobias Grosser  *        try {
1258d169d70bSTobias Grosser  *          stat ret = (*data->func)(manage(arg_0));
1259d169d70bSTobias Grosser  *          return isl_stat_ok;
1260d169d70bSTobias Grosser  *        } catch (...) {
1261d169d70bSTobias Grosser  *          data->eptr = std::current_exception();
1262d169d70bSTobias Grosser  *          return isl_stat_error;
1263d169d70bSTobias Grosser  *        }
1264d169d70bSTobias Grosser  *      };
1265d169d70bSTobias Grosser  *
1266d169d70bSTobias Grosser  * The pointer to the std::function C++ callback function is stored in
1267d169d70bSTobias Grosser  * a fn_data data structure for passing to the C callback function,
1268d169d70bSTobias Grosser  * along with an std::exception_ptr that is used to store any
1269d169d70bSTobias Grosser  * exceptions thrown in the C++ callback.
1270d169d70bSTobias Grosser  *
1271d169d70bSTobias Grosser  *      struct fn_data {
1272d169d70bSTobias Grosser  *        const std::function<stat(map)> *func;
1273d169d70bSTobias Grosser  *        std::exception_ptr eptr;
1274d169d70bSTobias Grosser  *      } fn_data = { &fn };
1275d169d70bSTobias Grosser  *
1276d169d70bSTobias Grosser  * This std::function object represents the actual user
1277d169d70bSTobias Grosser  * callback function together with the locally captured state at the caller.
1278d169d70bSTobias Grosser  *
1279d169d70bSTobias Grosser  * The lambda function is expected to be used as a C callback function
1280d169d70bSTobias Grosser  * where the lambda itself is provided as the function pointer and
1281d169d70bSTobias Grosser  * where the user void pointer is a pointer to fn_data.
1282d169d70bSTobias Grosser  * The std::function object is extracted from the pointer to fn_data
1283d169d70bSTobias Grosser  * inside the lambda function.
1284d169d70bSTobias Grosser  *
1285d169d70bSTobias Grosser  * The std::exception_ptr object is not added to fn_data
1286d169d70bSTobias Grosser  * if checked C++ bindings are being generated.
1287d169d70bSTobias Grosser  * The body of the generated lambda function then is as follows:
1288d169d70bSTobias Grosser  *
1289d169d70bSTobias Grosser  *        stat ret = (*data->func)(manage(arg_0));
1290d169d70bSTobias Grosser  *        return isl_stat(ret);
12916145b11cSTobias Grosser  *
12926145b11cSTobias Grosser  * If the C callback does not take its arguments, then
12936145b11cSTobias Grosser  * manage_copy is used instead of manage.
1294d169d70bSTobias Grosser  */
1295d169d70bSTobias Grosser void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param)
1296d169d70bSTobias Grosser {
1297d169d70bSTobias Grosser 	string pname;
1298d169d70bSTobias Grosser 	QualType ptype;
1299d169d70bSTobias Grosser 	string call, c_args, cpp_args, rettype, last_idx;
1300d169d70bSTobias Grosser 	const FunctionProtoType *callback;
1301d169d70bSTobias Grosser 	int num_params;
1302d169d70bSTobias Grosser 
1303d169d70bSTobias Grosser 	pname = param->getName().str();
1304d169d70bSTobias Grosser 	ptype = param->getType();
1305d169d70bSTobias Grosser 
1306d169d70bSTobias Grosser 	c_args = generate_callback_args(ptype, false);
1307d169d70bSTobias Grosser 	cpp_args = generate_callback_type(ptype);
1308d169d70bSTobias Grosser 
1309*26269d34STobias Grosser 	callback = extract_prototype(ptype);
1310d169d70bSTobias Grosser 	rettype = callback->getReturnType().getAsString();
1311d169d70bSTobias Grosser 	num_params = callback->getNumArgs();
1312d169d70bSTobias Grosser 
1313d169d70bSTobias Grosser 	last_idx = ::to_string(num_params - 1);
1314d169d70bSTobias Grosser 
1315d169d70bSTobias Grosser 	call = "(*data->func)(";
1316d169d70bSTobias Grosser 	for (long i = 0; i < num_params - 1; i++) {
13176145b11cSTobias Grosser 		if (!callback_takes_argument(param, i))
13186145b11cSTobias Grosser 			call += "manage_copy";
13196145b11cSTobias Grosser 		else
13206145b11cSTobias Grosser 			call += "manage";
13216145b11cSTobias Grosser 		call += "(arg_" + ::to_string(i) + ")";
1322d169d70bSTobias Grosser 		if (i != num_params - 2)
1323d169d70bSTobias Grosser 			call += ", ";
1324d169d70bSTobias Grosser 	}
1325d169d70bSTobias Grosser 	call += ")";
1326d169d70bSTobias Grosser 
1327d169d70bSTobias Grosser 	osprintf(os, "  struct %s_data {\n", pname.c_str());
1328d169d70bSTobias Grosser 	osprintf(os, "    const %s *func;\n", cpp_args.c_str());
1329d169d70bSTobias Grosser 	if (!checked)
1330d169d70bSTobias Grosser 		osprintf(os, "    std::exception_ptr eptr;\n");
1331d169d70bSTobias Grosser 	osprintf(os, "  } %s_data = { &%s };\n", pname.c_str(), pname.c_str());
1332d169d70bSTobias Grosser 	osprintf(os, "  auto %s_lambda = [](%s) -> %s {\n",
1333d169d70bSTobias Grosser 		 pname.c_str(), c_args.c_str(), rettype.c_str());
1334d169d70bSTobias Grosser 	osprintf(os,
1335d169d70bSTobias Grosser 		 "    auto *data = static_cast<struct %s_data *>(arg_%s);\n",
1336d169d70bSTobias Grosser 		 pname.c_str(), last_idx.c_str());
1337d169d70bSTobias Grosser 	print_wrapped_call(os, call);
1338d169d70bSTobias Grosser 	osprintf(os, "  };\n");
1339d169d70bSTobias Grosser }
1340d169d70bSTobias Grosser 
1341d169d70bSTobias Grosser /* An array listing functions that must be renamed and the function name they
1342d169d70bSTobias Grosser  * should be renamed to. We currently rename functions in case their name would
1343d169d70bSTobias Grosser  * match a reserved C++ keyword, which is not allowed in C++.
1344d169d70bSTobias Grosser  */
1345d169d70bSTobias Grosser static const char *rename_map[][2] = {
1346d169d70bSTobias Grosser 	{ "union", "unite" },
1347d169d70bSTobias Grosser };
1348d169d70bSTobias Grosser 
1349d169d70bSTobias Grosser /* Rename method "name" in case the method name in the C++ bindings should not
1350d169d70bSTobias Grosser  * match the name in the C bindings. We do this for example to avoid
1351d169d70bSTobias Grosser  * C++ keywords.
1352d169d70bSTobias Grosser  */
1353d169d70bSTobias Grosser std::string cpp_generator::rename_method(std::string name)
1354d169d70bSTobias Grosser {
1355d169d70bSTobias Grosser 	for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++)
1356d169d70bSTobias Grosser 		if (name.compare(rename_map[i][0]) == 0)
1357d169d70bSTobias Grosser 			return rename_map[i][1];
1358d169d70bSTobias Grosser 
1359d169d70bSTobias Grosser 	return name;
1360d169d70bSTobias Grosser }
1361d169d70bSTobias Grosser 
1362d169d70bSTobias Grosser /* Translate isl class "clazz" to its corresponding C++ type.
1363d169d70bSTobias Grosser  */
1364d169d70bSTobias Grosser string cpp_generator::type2cpp(const isl_class &clazz)
1365d169d70bSTobias Grosser {
1366d169d70bSTobias Grosser 	return type2cpp(clazz.name);
1367d169d70bSTobias Grosser }
1368d169d70bSTobias Grosser 
1369d169d70bSTobias Grosser /* Translate type string "type_str" to its C++ name counterpart.
1370d169d70bSTobias Grosser */
1371d169d70bSTobias Grosser string cpp_generator::type2cpp(string type_str)
1372d169d70bSTobias Grosser {
1373d169d70bSTobias Grosser 	return type_str.substr(4);
1374d169d70bSTobias Grosser }
1375d169d70bSTobias Grosser 
1376d169d70bSTobias Grosser /* Translate QualType "type" to its C++ name counterpart.
1377d169d70bSTobias Grosser  *
1378d169d70bSTobias Grosser  * An isl_bool return type is translated into "bool",
1379d169d70bSTobias Grosser  * while an isl_stat is translated into "void".
1380d169d70bSTobias Grosser  * The exceptional cases are handled through exceptions.
1381d169d70bSTobias Grosser  * If checked C++ bindings are being generated, then
1382d169d70bSTobias Grosser  * C++ counterparts of isl_bool and isl_stat need to be used instead.
1383d169d70bSTobias Grosser  */
1384d169d70bSTobias Grosser string cpp_generator::type2cpp(QualType type)
1385d169d70bSTobias Grosser {
1386d169d70bSTobias Grosser 	if (is_isl_type(type))
1387d169d70bSTobias Grosser 		return type2cpp(type->getPointeeType().getAsString());
1388d169d70bSTobias Grosser 
1389d169d70bSTobias Grosser 	if (is_isl_bool(type))
1390d169d70bSTobias Grosser 		return checked ? "boolean" : "bool";
1391d169d70bSTobias Grosser 
1392d169d70bSTobias Grosser 	if (is_isl_stat(type))
1393d169d70bSTobias Grosser 		return checked ? "stat" : "void";
1394d169d70bSTobias Grosser 
1395d169d70bSTobias Grosser 	if (type->isIntegerType())
1396d169d70bSTobias Grosser 		return type.getAsString();
1397d169d70bSTobias Grosser 
1398d169d70bSTobias Grosser 	if (is_string(type))
1399d169d70bSTobias Grosser 		return "std::string";
1400d169d70bSTobias Grosser 
1401d169d70bSTobias Grosser 	if (is_callback(type))
1402d169d70bSTobias Grosser 		return generate_callback_type(type);
1403d169d70bSTobias Grosser 
1404d169d70bSTobias Grosser 	die("Cannot convert type to C++ type");
1405d169d70bSTobias Grosser }
1406d169d70bSTobias Grosser 
1407d169d70bSTobias Grosser /* Check if "subclass_type" is a subclass of "class_type".
1408d169d70bSTobias Grosser  */
1409d169d70bSTobias Grosser bool cpp_generator::is_subclass(QualType subclass_type,
1410d169d70bSTobias Grosser 	const isl_class &class_type)
1411d169d70bSTobias Grosser {
1412d169d70bSTobias Grosser 	std::string type_str = subclass_type->getPointeeType().getAsString();
1413d169d70bSTobias Grosser 	std::vector<std::string> superclasses;
1414d169d70bSTobias Grosser 	std::vector<const isl_class *> parents;
1415d169d70bSTobias Grosser 	std::vector<std::string>::iterator ci;
1416d169d70bSTobias Grosser 
1417d169d70bSTobias Grosser 	superclasses = generator::find_superclasses(classes[type_str].type);
1418d169d70bSTobias Grosser 
1419d169d70bSTobias Grosser 	for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
1420d169d70bSTobias Grosser 		parents.push_back(&classes[*ci]);
1421d169d70bSTobias Grosser 
1422d169d70bSTobias Grosser 	while (!parents.empty()) {
1423d169d70bSTobias Grosser 		const isl_class *candidate = parents.back();
1424d169d70bSTobias Grosser 
1425d169d70bSTobias Grosser 		parents.pop_back();
1426d169d70bSTobias Grosser 
1427d169d70bSTobias Grosser 		if (&class_type == candidate)
1428d169d70bSTobias Grosser 			return true;
1429d169d70bSTobias Grosser 
1430d169d70bSTobias Grosser 		superclasses = generator::find_superclasses(candidate->type);
1431d169d70bSTobias Grosser 
1432d169d70bSTobias Grosser 		for (ci = superclasses.begin(); ci < superclasses.end(); ci++)
1433d169d70bSTobias Grosser 			parents.push_back(&classes[*ci]);
1434d169d70bSTobias Grosser 	}
1435d169d70bSTobias Grosser 
1436d169d70bSTobias Grosser 	return false;
1437d169d70bSTobias Grosser }
1438d169d70bSTobias Grosser 
1439d169d70bSTobias Grosser /* Check if "cons" is an implicit conversion constructor of class "clazz".
1440d169d70bSTobias Grosser  *
1441d169d70bSTobias Grosser  * An implicit conversion constructor is generated in case "cons" has a single
1442d169d70bSTobias Grosser  * parameter, where the parameter type is a subclass of the class that is
1443d169d70bSTobias Grosser  * currently being generated.
1444d169d70bSTobias Grosser  */
1445d169d70bSTobias Grosser bool cpp_generator::is_implicit_conversion(const isl_class &clazz,
1446d169d70bSTobias Grosser 	FunctionDecl *cons)
1447d169d70bSTobias Grosser {
1448d169d70bSTobias Grosser 	ParmVarDecl *param = cons->getParamDecl(0);
1449d169d70bSTobias Grosser 	QualType type = param->getOriginalType();
1450d169d70bSTobias Grosser 
1451d169d70bSTobias Grosser 	int num_params = cons->getNumParams();
1452d169d70bSTobias Grosser 	if (num_params != 1)
1453d169d70bSTobias Grosser 		return false;
1454d169d70bSTobias Grosser 
1455d169d70bSTobias Grosser 	if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz))
1456d169d70bSTobias Grosser 		return true;
1457d169d70bSTobias Grosser 
1458d169d70bSTobias Grosser 	return false;
1459d169d70bSTobias Grosser }
1460d169d70bSTobias Grosser 
1461d169d70bSTobias Grosser /* Get kind of "method" in "clazz".
1462d169d70bSTobias Grosser  *
1463d169d70bSTobias Grosser  * Given the declaration of a static or member method, returns its kind.
1464d169d70bSTobias Grosser  */
1465d169d70bSTobias Grosser cpp_generator::function_kind cpp_generator::get_method_kind(
1466d169d70bSTobias Grosser 	const isl_class &clazz, FunctionDecl *method)
1467d169d70bSTobias Grosser {
1468d169d70bSTobias Grosser 	if (is_static(clazz, method))
1469d169d70bSTobias Grosser 		return function_kind_static_method;
1470d169d70bSTobias Grosser 	else
1471d169d70bSTobias Grosser 		return function_kind_member_method;
1472d169d70bSTobias Grosser }
1473