xref: /llvm-project/polly/lib/External/isl/interface/plain_cpp.cc (revision a749e09e184b2b0b6dde71af01c82dd427b3e3e2)
13f9bf9f4Spatacca /*
23f9bf9f4Spatacca  * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
33f9bf9f4Spatacca  *
43f9bf9f4Spatacca  * Redistribution and use in source and binary forms, with or without
53f9bf9f4Spatacca  * modification, are permitted provided that the following conditions
63f9bf9f4Spatacca  * are met:
73f9bf9f4Spatacca  *
83f9bf9f4Spatacca  *    1. Redistributions of source code must retain the above copyright
93f9bf9f4Spatacca  *       notice, this list of conditions and the following disclaimer.
103f9bf9f4Spatacca  *
113f9bf9f4Spatacca  *    2. Redistributions in binary form must reproduce the above
123f9bf9f4Spatacca  *       copyright notice, this list of conditions and the following
133f9bf9f4Spatacca  *       disclaimer in the documentation and/or other materials provided
143f9bf9f4Spatacca  *       with the distribution.
153f9bf9f4Spatacca  *
163f9bf9f4Spatacca  * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY
173f9bf9f4Spatacca  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183f9bf9f4Spatacca  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
193f9bf9f4Spatacca  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOBIAS GROSSER OR
203f9bf9f4Spatacca  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
213f9bf9f4Spatacca  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
223f9bf9f4Spatacca  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
233f9bf9f4Spatacca  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243f9bf9f4Spatacca  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253f9bf9f4Spatacca  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263f9bf9f4Spatacca  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273f9bf9f4Spatacca  *
283f9bf9f4Spatacca  * The views and conclusions contained in the software and documentation
293f9bf9f4Spatacca  * are those of the authors and should not be interpreted as
303f9bf9f4Spatacca  * representing official policies, either expressed or implied, of
313f9bf9f4Spatacca  * Tobias Grosser.
323f9bf9f4Spatacca  */
333f9bf9f4Spatacca 
343f9bf9f4Spatacca #include <cstdarg>
353f9bf9f4Spatacca #include <cstdio>
363f9bf9f4Spatacca #include <iostream>
373f9bf9f4Spatacca #include <map>
383f9bf9f4Spatacca #include <memory>
393f9bf9f4Spatacca #include <sstream>
403f9bf9f4Spatacca #include <string>
413f9bf9f4Spatacca #include <vector>
423f9bf9f4Spatacca 
433f9bf9f4Spatacca #include "plain_cpp.h"
443f9bf9f4Spatacca #include "isl_config.h"
453f9bf9f4Spatacca 
463f9bf9f4Spatacca /* Print string formatted according to "fmt" to ostream "os".
473f9bf9f4Spatacca  *
483f9bf9f4Spatacca  * This osprintf method allows us to use printf style formatting constructs when
493f9bf9f4Spatacca  * writing to an ostream.
503f9bf9f4Spatacca  */
osprintf(ostream & os,const char * format,va_list arguments)513f9bf9f4Spatacca static void osprintf(ostream &os, const char *format, va_list arguments)
523f9bf9f4Spatacca {
533f9bf9f4Spatacca 	va_list copy;
543f9bf9f4Spatacca 	char *string_pointer;
553f9bf9f4Spatacca 	size_t size;
563f9bf9f4Spatacca 
573f9bf9f4Spatacca 	va_copy(copy, arguments);
583f9bf9f4Spatacca 	size = vsnprintf(NULL, 0, format, copy);
593f9bf9f4Spatacca 	string_pointer = new char[size + 1];
603f9bf9f4Spatacca 	va_end(copy);
613f9bf9f4Spatacca 	vsnprintf(string_pointer, size + 1, format, arguments);
623f9bf9f4Spatacca 	os << string_pointer;
633f9bf9f4Spatacca 	delete[] string_pointer;
643f9bf9f4Spatacca }
653f9bf9f4Spatacca 
663f9bf9f4Spatacca /* Print string formatted according to "fmt" to ostream "os".
673f9bf9f4Spatacca  *
683f9bf9f4Spatacca  * This osprintf method allows us to use printf style formatting constructs when
693f9bf9f4Spatacca  * writing to an ostream.
703f9bf9f4Spatacca  */
osprintf(ostream & os,const char * format,...)713f9bf9f4Spatacca static void osprintf(ostream &os, const char *format, ...)
723f9bf9f4Spatacca {
733f9bf9f4Spatacca 	va_list arguments;
743f9bf9f4Spatacca 
753f9bf9f4Spatacca 	va_start(arguments, format);
763f9bf9f4Spatacca 	osprintf(os, format, arguments);
773f9bf9f4Spatacca 	va_end(arguments);
783f9bf9f4Spatacca }
793f9bf9f4Spatacca 
803f9bf9f4Spatacca /* Print string formatted according to "fmt" to ostream "os"
813f9bf9f4Spatacca  * with the given indentation.
823f9bf9f4Spatacca  *
833f9bf9f4Spatacca  * This osprintf method allows us to use printf style formatting constructs when
843f9bf9f4Spatacca  * writing to an ostream.
853f9bf9f4Spatacca  */
osprintf(ostream & os,int indent,const char * format,...)863f9bf9f4Spatacca static void osprintf(ostream &os, int indent, const char *format, ...)
873f9bf9f4Spatacca {
883f9bf9f4Spatacca 	va_list arguments;
893f9bf9f4Spatacca 
903f9bf9f4Spatacca 	osprintf(os, "%*s", indent, " ");
913f9bf9f4Spatacca 	va_start(arguments, format);
923f9bf9f4Spatacca 	osprintf(os, format, arguments);
933f9bf9f4Spatacca 	va_end(arguments);
943f9bf9f4Spatacca }
953f9bf9f4Spatacca 
963f9bf9f4Spatacca /* Convert "l" to a string.
973f9bf9f4Spatacca  */
to_string(long l)983f9bf9f4Spatacca static std::string to_string(long l)
993f9bf9f4Spatacca {
1003f9bf9f4Spatacca 	std::ostringstream strm;
1013f9bf9f4Spatacca 	strm << l;
1023f9bf9f4Spatacca 	return strm.str();
1033f9bf9f4Spatacca }
1043f9bf9f4Spatacca 
1053f9bf9f4Spatacca /* Construct a generator for plain C++ bindings.
1063f9bf9f4Spatacca  *
1073f9bf9f4Spatacca  * "checked" is set if C++ bindings should be generated
1083f9bf9f4Spatacca  * that rely on the user to check for error conditions.
1093f9bf9f4Spatacca  */
plain_cpp_generator(SourceManager & SM,set<RecordDecl * > & exported_types,set<FunctionDecl * > exported_functions,set<FunctionDecl * > functions,bool checked)1103f9bf9f4Spatacca plain_cpp_generator::plain_cpp_generator(SourceManager &SM,
1113f9bf9f4Spatacca 	set<RecordDecl *> &exported_types,
1123f9bf9f4Spatacca 	set<FunctionDecl *> exported_functions, set<FunctionDecl *> functions,
1133f9bf9f4Spatacca 	bool checked) :
1143f9bf9f4Spatacca 		cpp_generator(SM, exported_types, exported_functions,
1153f9bf9f4Spatacca 			functions),
1163f9bf9f4Spatacca 		checked(checked)
1173f9bf9f4Spatacca {
1183f9bf9f4Spatacca }
1193f9bf9f4Spatacca 
1203f9bf9f4Spatacca /* Generate a cpp interface based on the extracted types and functions.
1213f9bf9f4Spatacca  *
1223f9bf9f4Spatacca  * Print first a set of forward declarations for all isl wrapper
1233f9bf9f4Spatacca  * classes, then the declarations of the classes, and at the end all
1243f9bf9f4Spatacca  * implementations.
1253f9bf9f4Spatacca  *
1263f9bf9f4Spatacca  * If checked C++ bindings are being generated,
1273f9bf9f4Spatacca  * then wrap them in a namespace to avoid conflicts
1283f9bf9f4Spatacca  * with the default C++ bindings (with automatic checks using exceptions).
1293f9bf9f4Spatacca  */
generate()1303f9bf9f4Spatacca void plain_cpp_generator::generate()
1313f9bf9f4Spatacca {
1323f9bf9f4Spatacca 	ostream &os = cout;
1333f9bf9f4Spatacca 
1343f9bf9f4Spatacca 	osprintf(os, "\n");
1353f9bf9f4Spatacca 	osprintf(os, "namespace isl {\n\n");
1363f9bf9f4Spatacca 	if (checked)
1373f9bf9f4Spatacca 		osprintf(os, "namespace checked {\n\n");
1383f9bf9f4Spatacca 
1393f9bf9f4Spatacca 	print_forward_declarations(os);
1403f9bf9f4Spatacca 	osprintf(os, "\n");
1413f9bf9f4Spatacca 	print_declarations(os);
1423f9bf9f4Spatacca 	osprintf(os, "\n");
1433f9bf9f4Spatacca 	print_implementations(os);
1443f9bf9f4Spatacca 
1453f9bf9f4Spatacca 	if (checked)
1463f9bf9f4Spatacca 		osprintf(os, "} // namespace checked\n");
1473f9bf9f4Spatacca 	osprintf(os, "} // namespace isl\n");
1483f9bf9f4Spatacca }
1493f9bf9f4Spatacca 
1503f9bf9f4Spatacca /* Print forward declarations for all classes to "os".
1513f9bf9f4Spatacca */
print_forward_declarations(ostream & os)1523f9bf9f4Spatacca void plain_cpp_generator::print_forward_declarations(ostream &os)
1533f9bf9f4Spatacca {
1543f9bf9f4Spatacca 	map<string, isl_class>::iterator ci;
1553f9bf9f4Spatacca 
1563f9bf9f4Spatacca 	osprintf(os, "// forward declarations\n");
1573f9bf9f4Spatacca 
1583f9bf9f4Spatacca 	for (ci = classes.begin(); ci != classes.end(); ++ci)
1593f9bf9f4Spatacca 		print_class_forward_decl(os, ci->second);
1603f9bf9f4Spatacca }
1613f9bf9f4Spatacca 
1623f9bf9f4Spatacca /* Print all declarations to "os".
1633f9bf9f4Spatacca  */
print_declarations(ostream & os)1643f9bf9f4Spatacca void plain_cpp_generator::print_declarations(ostream &os)
1653f9bf9f4Spatacca {
1663f9bf9f4Spatacca 	map<string, isl_class>::iterator ci;
1673f9bf9f4Spatacca 	bool first = true;
1683f9bf9f4Spatacca 
1693f9bf9f4Spatacca 	for (ci = classes.begin(); ci != classes.end(); ++ci) {
1703f9bf9f4Spatacca 		if (first)
1713f9bf9f4Spatacca 			first = false;
1723f9bf9f4Spatacca 		else
1733f9bf9f4Spatacca 			osprintf(os, "\n");
1743f9bf9f4Spatacca 
1753f9bf9f4Spatacca 		print_class(os, ci->second);
1763f9bf9f4Spatacca 	}
1773f9bf9f4Spatacca }
1783f9bf9f4Spatacca 
1793f9bf9f4Spatacca /* Print all implementations to "os".
1803f9bf9f4Spatacca  */
print_implementations(ostream & os)1813f9bf9f4Spatacca void plain_cpp_generator::print_implementations(ostream &os)
1823f9bf9f4Spatacca {
1833f9bf9f4Spatacca 	map<string, isl_class>::iterator ci;
1843f9bf9f4Spatacca 	bool first = true;
1853f9bf9f4Spatacca 
1863f9bf9f4Spatacca 	for (ci = classes.begin(); ci != classes.end(); ++ci) {
1873f9bf9f4Spatacca 		if (first)
1883f9bf9f4Spatacca 			first = false;
1893f9bf9f4Spatacca 		else
1903f9bf9f4Spatacca 			osprintf(os, "\n");
1913f9bf9f4Spatacca 
1923f9bf9f4Spatacca 		print_class_impl(os, ci->second);
1933f9bf9f4Spatacca 	}
1943f9bf9f4Spatacca }
1953f9bf9f4Spatacca 
1963f9bf9f4Spatacca /* If the printed class is a subclass that is based on a type function,
1973f9bf9f4Spatacca  * then introduce a "type" field that holds the value of the type
1983f9bf9f4Spatacca  * corresponding to the subclass and make the fields of the class
1993f9bf9f4Spatacca  * accessible to the "isa" and "as" methods of the (immediate) superclass.
2003f9bf9f4Spatacca  * In particular, "isa" needs access to the type field itself,
2013f9bf9f4Spatacca  * while "as" needs access to the private constructor.
2023f9bf9f4Spatacca  * In case of the "isa" method, all instances are made friends
2033f9bf9f4Spatacca  * to avoid access right confusion.
2043f9bf9f4Spatacca  */
print_subclass_type()2053f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_subclass_type()
2063f9bf9f4Spatacca {
2073f9bf9f4Spatacca 	std::string super;
2083f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
2093f9bf9f4Spatacca 	const char *supername;
2103f9bf9f4Spatacca 
2113f9bf9f4Spatacca 	if (!clazz.is_type_subclass())
2123f9bf9f4Spatacca 		return;
2133f9bf9f4Spatacca 
2143f9bf9f4Spatacca 	super = type2cpp(clazz.superclass_name);
2153f9bf9f4Spatacca 	supername = super.c_str();
2163f9bf9f4Spatacca 	osprintf(os, "  template <class T>\n");
2173f9bf9f4Spatacca 	osprintf(os, "  friend %s %s::isa() const;\n",
2183f9bf9f4Spatacca 		generator.isl_bool2cpp().c_str(), supername);
2193f9bf9f4Spatacca 	osprintf(os, "  friend %s %s::as<%s>() const;\n",
2203f9bf9f4Spatacca 		cppname, supername, cppname);
2213f9bf9f4Spatacca 	osprintf(os, "  static const auto type = %s;\n",
2223f9bf9f4Spatacca 		clazz.subclass_name.c_str());
2233f9bf9f4Spatacca }
2243f9bf9f4Spatacca 
2253f9bf9f4Spatacca /* Print declarations for class "clazz" to "os".
2263f9bf9f4Spatacca  *
2273f9bf9f4Spatacca  * If "clazz" is a subclass based on a type function,
2283f9bf9f4Spatacca  * then it is made to inherit from the (immediate) superclass and
2293f9bf9f4Spatacca  * a "type" attribute is added for use in the "as" and "isa"
2303f9bf9f4Spatacca  * methods of the superclass.
2313f9bf9f4Spatacca  *
2323f9bf9f4Spatacca  * Conversely, if "clazz" is a superclass with a type function,
2333f9bf9f4Spatacca  * then declare those "as" and "isa" methods.
2343f9bf9f4Spatacca  *
2353f9bf9f4Spatacca  * The pointer to the isl object is only added for classes that
2363f9bf9f4Spatacca  * are not subclasses, since subclasses refer to the same isl object.
2373f9bf9f4Spatacca  */
print_class(ostream & os,const isl_class & clazz)2383f9bf9f4Spatacca void plain_cpp_generator::print_class(ostream &os, const isl_class &clazz)
2393f9bf9f4Spatacca {
2403f9bf9f4Spatacca 	decl_printer printer(os, clazz, *this);
2413f9bf9f4Spatacca 	const char *name = clazz.name.c_str();
2423f9bf9f4Spatacca 	const char *cppname = printer.cppstring.c_str();
2433f9bf9f4Spatacca 
2443f9bf9f4Spatacca 	osprintf(os, "// declarations for isl::%s\n", cppname);
2453f9bf9f4Spatacca 
2463f9bf9f4Spatacca 	printer.print_class_factory();
2473f9bf9f4Spatacca 	osprintf(os, "\n");
2483f9bf9f4Spatacca 	osprintf(os, "class %s ", cppname);
2493f9bf9f4Spatacca 	if (clazz.is_type_subclass())
2503f9bf9f4Spatacca 		osprintf(os, ": public %s ",
2513f9bf9f4Spatacca 			type2cpp(clazz.superclass_name).c_str());
2523f9bf9f4Spatacca 	osprintf(os, "{\n");
2533f9bf9f4Spatacca 	printer.print_subclass_type();
2543f9bf9f4Spatacca 	printer.print_class_factory("  friend ");
2553f9bf9f4Spatacca 	osprintf(os, "\n");
2563f9bf9f4Spatacca 	osprintf(os, "protected:\n");
2573f9bf9f4Spatacca 	if (!clazz.is_type_subclass()) {
2583f9bf9f4Spatacca 		osprintf(os, "  %s *ptr = nullptr;\n", name);
2593f9bf9f4Spatacca 		osprintf(os, "\n");
2603f9bf9f4Spatacca 	}
2613f9bf9f4Spatacca 	printer.print_protected_constructors();
2623f9bf9f4Spatacca 	osprintf(os, "\n");
2633f9bf9f4Spatacca 	osprintf(os, "public:\n");
264*a749e09eSMichael Kruse 	printer.print_public_methods();
2653f9bf9f4Spatacca 
2663f9bf9f4Spatacca 	osprintf(os, "};\n");
2673f9bf9f4Spatacca }
2683f9bf9f4Spatacca 
2693f9bf9f4Spatacca /* Print forward declaration of class "clazz" to "os".
2703f9bf9f4Spatacca  */
print_class_forward_decl(ostream & os,const isl_class & clazz)2713f9bf9f4Spatacca void plain_cpp_generator::print_class_forward_decl(ostream &os,
2723f9bf9f4Spatacca 	const isl_class &clazz)
2733f9bf9f4Spatacca {
2743f9bf9f4Spatacca 	std::string cppstring = type2cpp(clazz);
2753f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
2763f9bf9f4Spatacca 
2773f9bf9f4Spatacca 	osprintf(os, "class %s;\n", cppname);
2783f9bf9f4Spatacca }
2793f9bf9f4Spatacca 
2803f9bf9f4Spatacca /* Print global factory functions.
2813f9bf9f4Spatacca  *
2823f9bf9f4Spatacca  * Each class has two global factory functions:
2833f9bf9f4Spatacca  *
2843f9bf9f4Spatacca  * 	set manage(__isl_take isl_set *ptr);
2853f9bf9f4Spatacca  * 	set manage_copy(__isl_keep isl_set *ptr);
2863f9bf9f4Spatacca  *
2873f9bf9f4Spatacca  * A user can construct isl C++ objects from a raw pointer and indicate whether
2883f9bf9f4Spatacca  * they intend to take the ownership of the object or not through these global
2893f9bf9f4Spatacca  * factory functions. This ensures isl object creation is very explicit and
2903f9bf9f4Spatacca  * pointers are not converted by accident. Thanks to overloading, manage() and
2913f9bf9f4Spatacca  * manage_copy() can be called on any isl raw pointer and the corresponding
2923f9bf9f4Spatacca  * object is automatically created, without the user having to choose the right
2933f9bf9f4Spatacca  * isl object type.
2943f9bf9f4Spatacca  *
2953f9bf9f4Spatacca  * For a subclass based on a type function, no factory functions
2963f9bf9f4Spatacca  * are introduced because they share the C object type with
2973f9bf9f4Spatacca  * the superclass.
2983f9bf9f4Spatacca  */
print_class_factory(const std::string & prefix)2993f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_class_factory(
3003f9bf9f4Spatacca 	const std::string &prefix)
3013f9bf9f4Spatacca {
3023f9bf9f4Spatacca 	const char *name = clazz.name.c_str();
3033f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
3043f9bf9f4Spatacca 
3053f9bf9f4Spatacca 	if (clazz.is_type_subclass())
3063f9bf9f4Spatacca 		return;
3073f9bf9f4Spatacca 
3083f9bf9f4Spatacca 	os << prefix;
3093f9bf9f4Spatacca 	osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name);
3103f9bf9f4Spatacca 	os << prefix;
3113f9bf9f4Spatacca 	osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n",
3123f9bf9f4Spatacca 		cppname, name);
3133f9bf9f4Spatacca }
3143f9bf9f4Spatacca 
3153f9bf9f4Spatacca /* Print declarations of protected constructors.
3163f9bf9f4Spatacca  *
3173f9bf9f4Spatacca  * Each class has currently one protected constructor:
3183f9bf9f4Spatacca  *
3193f9bf9f4Spatacca  * 	1) Constructor from a plain isl_* C pointer
3203f9bf9f4Spatacca  *
3213f9bf9f4Spatacca  * Example:
3223f9bf9f4Spatacca  *
3233f9bf9f4Spatacca  * 	set(__isl_take isl_set *ptr);
3243f9bf9f4Spatacca  *
3253f9bf9f4Spatacca  * The raw pointer constructor is kept protected. Object creation is only
3263f9bf9f4Spatacca  * possible through manage() or manage_copy().
3273f9bf9f4Spatacca  */
print_protected_constructors()3283f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_protected_constructors()
3293f9bf9f4Spatacca {
3303f9bf9f4Spatacca 	const char *name = clazz.name.c_str();
3313f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
3323f9bf9f4Spatacca 
3333f9bf9f4Spatacca 	osprintf(os, "  inline explicit %s(__isl_take %s *ptr);\n", cppname,
3343f9bf9f4Spatacca 		 name);
3353f9bf9f4Spatacca }
3363f9bf9f4Spatacca 
3373f9bf9f4Spatacca /* Print declarations of public constructors.
3383f9bf9f4Spatacca  *
3393f9bf9f4Spatacca  * Each class currently has two public constructors:
3403f9bf9f4Spatacca  *
3413f9bf9f4Spatacca  * 	1) A default constructor
3423f9bf9f4Spatacca  * 	2) A copy constructor
3433f9bf9f4Spatacca  *
3443f9bf9f4Spatacca  * Example:
3453f9bf9f4Spatacca  *
3463f9bf9f4Spatacca  *	set();
3473f9bf9f4Spatacca  *	set(const set &set);
3483f9bf9f4Spatacca  */
print_public_constructors()3493f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_public_constructors()
3503f9bf9f4Spatacca {
3513f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
3523f9bf9f4Spatacca 	osprintf(os, "  inline /* implicit */ %s();\n", cppname);
3533f9bf9f4Spatacca 
3543f9bf9f4Spatacca 	osprintf(os, "  inline /* implicit */ %s(const %s &obj);\n",
3553f9bf9f4Spatacca 		 cppname, cppname);
3563f9bf9f4Spatacca }
3573f9bf9f4Spatacca 
3583f9bf9f4Spatacca /* Print declarations for "method".
3593f9bf9f4Spatacca  */
print_method(const ConversionMethod & method)3603f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_method(
3613f9bf9f4Spatacca 	const ConversionMethod &method)
3623f9bf9f4Spatacca {
3633f9bf9f4Spatacca 	print_full_method_header(method);
3643f9bf9f4Spatacca }
3653f9bf9f4Spatacca 
3663f9bf9f4Spatacca /* Print declarations for "method".
3673f9bf9f4Spatacca  */
print_method(const Method & method)3683f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_method(const Method &method)
3693f9bf9f4Spatacca {
3703f9bf9f4Spatacca 	print_full_method_header(method);
3713f9bf9f4Spatacca }
3723f9bf9f4Spatacca 
373*a749e09eSMichael Kruse /* Print a declaration for a constructor for the "id" class
374*a749e09eSMichael Kruse  * that takes a user object.
375*a749e09eSMichael Kruse  */
print_id_constructor_user()376*a749e09eSMichael Kruse void plain_cpp_generator::decl_printer::print_id_constructor_user()
377*a749e09eSMichael Kruse {
378*a749e09eSMichael Kruse 	print_id_constructor_user_header();
379*a749e09eSMichael Kruse }
380*a749e09eSMichael Kruse 
381*a749e09eSMichael Kruse /* Print a declaration for an "id" method
382*a749e09eSMichael Kruse  * for retrieving the user object associated to the identifier.
383*a749e09eSMichael Kruse  * If "optional" is set, the method returns a std::optional user object.
384*a749e09eSMichael Kruse  */
print_id_user(bool optional)385*a749e09eSMichael Kruse void plain_cpp_generator::decl_printer::print_id_user(bool optional)
386*a749e09eSMichael Kruse {
387*a749e09eSMichael Kruse 	print_id_user_header(optional);
388*a749e09eSMichael Kruse }
389*a749e09eSMichael Kruse 
3903f9bf9f4Spatacca /* Print declarations of copy assignment operator.
3913f9bf9f4Spatacca  *
3923f9bf9f4Spatacca  * Each class has one assignment operator.
3933f9bf9f4Spatacca  *
3943f9bf9f4Spatacca  * 	isl:set &set::operator=(set obj)
3953f9bf9f4Spatacca  *
3963f9bf9f4Spatacca  */
print_copy_assignment()3973f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_copy_assignment()
3983f9bf9f4Spatacca {
3993f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
4003f9bf9f4Spatacca 
4013f9bf9f4Spatacca 	osprintf(os, "  inline %s &operator=(%s obj);\n", cppname, cppname);
4023f9bf9f4Spatacca }
4033f9bf9f4Spatacca 
4043f9bf9f4Spatacca /* Print declaration of destructor.
4053f9bf9f4Spatacca  *
4063f9bf9f4Spatacca  * No explicit destructor is needed for type based subclasses.
4073f9bf9f4Spatacca  */
print_destructor()4083f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_destructor()
4093f9bf9f4Spatacca {
4103f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
4113f9bf9f4Spatacca 
4123f9bf9f4Spatacca 	if (clazz.is_type_subclass())
4133f9bf9f4Spatacca 		return;
4143f9bf9f4Spatacca 
4153f9bf9f4Spatacca 	osprintf(os, "  inline ~%s();\n", cppname);
4163f9bf9f4Spatacca }
4173f9bf9f4Spatacca 
4183f9bf9f4Spatacca /* Print declaration of pointer functions.
4193f9bf9f4Spatacca  * Since type based subclasses share the pointer with their superclass,
4203f9bf9f4Spatacca  * they can also reuse these functions from the superclass.
4213f9bf9f4Spatacca  *
4223f9bf9f4Spatacca  * To obtain a raw pointer three functions are provided:
4233f9bf9f4Spatacca  *
4243f9bf9f4Spatacca  * 	1) __isl_give isl_set *copy()
4253f9bf9f4Spatacca  *
4263f9bf9f4Spatacca  * 	  Returns a pointer to a _copy_ of the internal object
4273f9bf9f4Spatacca  *
4283f9bf9f4Spatacca  * 	2) __isl_keep isl_set *get()
4293f9bf9f4Spatacca  *
4303f9bf9f4Spatacca  * 	  Returns a pointer to the internal object
4313f9bf9f4Spatacca  *
4323f9bf9f4Spatacca  * 	3) __isl_give isl_set *release()
4333f9bf9f4Spatacca  *
4343f9bf9f4Spatacca  * 	  Returns a pointer to the internal object and resets the
4353f9bf9f4Spatacca  * 	  internal pointer to nullptr.
4363f9bf9f4Spatacca  *
4373f9bf9f4Spatacca  * We also provide functionality to explicitly check if a pointer is
4383f9bf9f4Spatacca  * currently managed by this object.
4393f9bf9f4Spatacca  *
4403f9bf9f4Spatacca  * 	4) bool is_null()
4413f9bf9f4Spatacca  *
4423f9bf9f4Spatacca  * 	  Check if the current object is a null pointer.
4433f9bf9f4Spatacca  *
4443f9bf9f4Spatacca  * The functions get() and release() model the value_ptr proposed in
4453f9bf9f4Spatacca  * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
4463f9bf9f4Spatacca  * The copy() function is an extension to allow the user to explicitly
4473f9bf9f4Spatacca  * copy the underlying object.
4483f9bf9f4Spatacca  *
4493f9bf9f4Spatacca  * Also generate a declaration to delete copy() for r-values, for
4503f9bf9f4Spatacca  * r-values release() should be used to avoid unnecessary copies.
4513f9bf9f4Spatacca  */
print_ptr()4523f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_ptr()
4533f9bf9f4Spatacca {
4543f9bf9f4Spatacca 	const char *name = clazz.name.c_str();
4553f9bf9f4Spatacca 
4563f9bf9f4Spatacca 	if (clazz.is_type_subclass())
4573f9bf9f4Spatacca 		return;
4583f9bf9f4Spatacca 
4593f9bf9f4Spatacca 	osprintf(os, "  inline __isl_give %s *copy() const &;\n", name);
4603f9bf9f4Spatacca 	osprintf(os, "  inline __isl_give %s *copy() && = delete;\n", name);
4613f9bf9f4Spatacca 	osprintf(os, "  inline __isl_keep %s *get() const;\n", name);
4623f9bf9f4Spatacca 	osprintf(os, "  inline __isl_give %s *release();\n", name);
4633f9bf9f4Spatacca 	osprintf(os, "  inline bool is_null() const;\n");
4643f9bf9f4Spatacca }
4653f9bf9f4Spatacca 
4663f9bf9f4Spatacca /* Print a template declaration with given indentation
4673f9bf9f4Spatacca  * for the "isa_type" method that ensures it is only enabled
4683f9bf9f4Spatacca  * when called with a template argument
4693f9bf9f4Spatacca  * that represents a type that is equal to that
4703f9bf9f4Spatacca  * of the return type of the type function of "super".
4713f9bf9f4Spatacca  * In particular, "isa_type" gets called from "isa"
4723f9bf9f4Spatacca  * with as template argument the type of the "type" field
4733f9bf9f4Spatacca  * of the subclass.
4743f9bf9f4Spatacca  * The check ensures that this subclass is in fact a direct subclass
4753f9bf9f4Spatacca  * of "super".
4763f9bf9f4Spatacca  */
print_isa_type_template(int indent,const isl_class & super)4773f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_isa_type_template(int indent,
4783f9bf9f4Spatacca 	const isl_class &super)
4793f9bf9f4Spatacca {
4803f9bf9f4Spatacca 	osprintf(os, indent,
4813f9bf9f4Spatacca 		"template <typename T,\n");
4823f9bf9f4Spatacca 	osprintf(os, indent,
4833f9bf9f4Spatacca 		"        typename = typename std::enable_if<std::is_same<\n");
4843f9bf9f4Spatacca 	osprintf(os, indent,
4853f9bf9f4Spatacca 		"                const decltype(%s(NULL)),\n",
4863f9bf9f4Spatacca 		super.fn_type->getNameAsString().c_str());
4873f9bf9f4Spatacca 	osprintf(os, indent,
4883f9bf9f4Spatacca 		"                const T>::value>::type>\n");
4893f9bf9f4Spatacca }
4903f9bf9f4Spatacca 
4913f9bf9f4Spatacca /* Print declarations for the "as" and "isa" methods, if the printed class
4923f9bf9f4Spatacca  * is a superclass with a type function.
4933f9bf9f4Spatacca  *
4943f9bf9f4Spatacca  * "isa" checks whether an object is of a given subclass type.
4953f9bf9f4Spatacca  * "isa_type" does the same, but gets passed the value of the type field
4963f9bf9f4Spatacca  * of the subclass as a function argument and the type of this field
4973f9bf9f4Spatacca  * as a template argument.
4983f9bf9f4Spatacca  * "as" tries to cast an object to a given subclass type, returning
4993f9bf9f4Spatacca  * an invalid object if the object is not of the given type.
5003f9bf9f4Spatacca  */
print_downcast()5013f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_downcast()
5023f9bf9f4Spatacca {
5033f9bf9f4Spatacca 	if (!clazz.fn_type)
5043f9bf9f4Spatacca 		return;
5053f9bf9f4Spatacca 
5063f9bf9f4Spatacca 	osprintf(os, "private:\n");
5073f9bf9f4Spatacca 	print_isa_type_template(2, clazz);
5083f9bf9f4Spatacca 	osprintf(os, "  inline %s isa_type(T subtype) const;\n",
5093f9bf9f4Spatacca 		generator.isl_bool2cpp().c_str());
5103f9bf9f4Spatacca 	osprintf(os, "public:\n");
5113f9bf9f4Spatacca 	osprintf(os, "  template <class T> inline %s isa() const;\n",
5123f9bf9f4Spatacca 		generator.isl_bool2cpp().c_str());
5133f9bf9f4Spatacca 	osprintf(os, "  template <class T> inline T as() const;\n");
5143f9bf9f4Spatacca }
5153f9bf9f4Spatacca 
5163f9bf9f4Spatacca /* Print the declaration of the ctx method.
5173f9bf9f4Spatacca  */
print_ctx()5183f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_ctx()
5193f9bf9f4Spatacca {
5203f9bf9f4Spatacca 	std::string ns = generator.isl_namespace();
5213f9bf9f4Spatacca 
5223f9bf9f4Spatacca 	osprintf(os, "  inline %sctx ctx() const;\n", ns.c_str());
5233f9bf9f4Spatacca }
5243f9bf9f4Spatacca 
525*a749e09eSMichael Kruse /* Print a separator between groups of method declarations.
526*a749e09eSMichael Kruse  */
print_method_separator()527*a749e09eSMichael Kruse void plain_cpp_generator::decl_printer::print_method_separator()
528*a749e09eSMichael Kruse {
529*a749e09eSMichael Kruse 	os << "\n";
530*a749e09eSMichael Kruse }
531*a749e09eSMichael Kruse 
5323f9bf9f4Spatacca /* Add a space to the return type "type" if needed,
5333f9bf9f4Spatacca  * i.e., if it is not the type of a pointer.
5343f9bf9f4Spatacca  */
add_space_to_return_type(const string & type)5353f9bf9f4Spatacca static string add_space_to_return_type(const string &type)
5363f9bf9f4Spatacca {
5373f9bf9f4Spatacca 	if (type[type.size() - 1] == '*')
5383f9bf9f4Spatacca 		return type;
5393f9bf9f4Spatacca 	return type + " ";
5403f9bf9f4Spatacca }
5413f9bf9f4Spatacca 
5423f9bf9f4Spatacca /* Print the prototype of the static inline method that is used
5433f9bf9f4Spatacca  * as the C callback set by "method".
5443f9bf9f4Spatacca  */
print_persistent_callback_prototype(FunctionDecl * method)5453f9bf9f4Spatacca void plain_cpp_generator::plain_printer::print_persistent_callback_prototype(
5463f9bf9f4Spatacca 	FunctionDecl *method)
5473f9bf9f4Spatacca {
5483f9bf9f4Spatacca 	string callback_name, rettype, c_args;
5493f9bf9f4Spatacca 	ParmVarDecl *param = persistent_callback_arg(method);
5503f9bf9f4Spatacca 	const FunctionProtoType *callback;
5513f9bf9f4Spatacca 	QualType ptype;
5523f9bf9f4Spatacca 	string classname;
5533f9bf9f4Spatacca 
5543f9bf9f4Spatacca 	ptype = param->getType();
5553f9bf9f4Spatacca 	callback = extract_prototype(ptype);
5563f9bf9f4Spatacca 
5573f9bf9f4Spatacca 	rettype = callback->getReturnType().getAsString();
5583f9bf9f4Spatacca 	rettype = add_space_to_return_type(rettype);
5593f9bf9f4Spatacca 	callback_name = clazz.persistent_callback_name(method);
5603f9bf9f4Spatacca 	c_args = generator.generate_callback_args(ptype, false);
5613f9bf9f4Spatacca 
5623f9bf9f4Spatacca 	if (!declarations)
5633f9bf9f4Spatacca 		classname = type2cpp(clazz) + "::";
5643f9bf9f4Spatacca 
5653f9bf9f4Spatacca 	osprintf(os, "%s%s%s(%s)",
5663f9bf9f4Spatacca 		 rettype.c_str(), classname.c_str(),
5673f9bf9f4Spatacca 		 callback_name.c_str(), c_args.c_str());
5683f9bf9f4Spatacca }
5693f9bf9f4Spatacca 
5703f9bf9f4Spatacca /* Print the prototype of the method for setting the callback function
5713f9bf9f4Spatacca  * set by "method".
5723f9bf9f4Spatacca  */
5733f9bf9f4Spatacca void
print_persistent_callback_setter_prototype(FunctionDecl * method)5743f9bf9f4Spatacca plain_cpp_generator::plain_printer::print_persistent_callback_setter_prototype(
5753f9bf9f4Spatacca 	FunctionDecl *method)
5763f9bf9f4Spatacca {
5773f9bf9f4Spatacca 	string classname, callback_name, cpptype;
5783f9bf9f4Spatacca 	ParmVarDecl *param = persistent_callback_arg(method);
5793f9bf9f4Spatacca 
5803f9bf9f4Spatacca 	if (!declarations)
5813f9bf9f4Spatacca 		classname = type2cpp(clazz) + "::";
5823f9bf9f4Spatacca 
5833f9bf9f4Spatacca 	cpptype = generator.param2cpp(param->getOriginalType());
5843f9bf9f4Spatacca 	callback_name = clazz.persistent_callback_name(method);
5853f9bf9f4Spatacca 	osprintf(os, "void %sset_%s_data(const %s &%s)",
5863f9bf9f4Spatacca 		classname.c_str(), callback_name.c_str(), cpptype.c_str(),
5873f9bf9f4Spatacca 		param->getName().str().c_str());
5883f9bf9f4Spatacca }
5893f9bf9f4Spatacca 
5903f9bf9f4Spatacca /* Given a method "method" for setting a persistent callback,
5913f9bf9f4Spatacca  * print the fields that are needed for marshalling the callback.
5923f9bf9f4Spatacca  *
5933f9bf9f4Spatacca  * In particular, print
5943f9bf9f4Spatacca  * - the declaration of a data structure for storing the C++ callback function
5953f9bf9f4Spatacca  * - a shared pointer to such a data structure
5963f9bf9f4Spatacca  * - the declaration of a static inline method
5973f9bf9f4Spatacca  *   for use as the C callback function
5983f9bf9f4Spatacca  * - the declaration of a private method for setting the callback function
5993f9bf9f4Spatacca  */
print_persistent_callback_data(FunctionDecl * method)6003f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_persistent_callback_data(
6013f9bf9f4Spatacca 	FunctionDecl *method)
6023f9bf9f4Spatacca {
6033f9bf9f4Spatacca 	string callback_name;
6043f9bf9f4Spatacca 	ParmVarDecl *param = generator.persistent_callback_arg(method);
6053f9bf9f4Spatacca 
6063f9bf9f4Spatacca 	callback_name = clazz.persistent_callback_name(method);
6073f9bf9f4Spatacca 	print_callback_data_decl(param, callback_name);
6083f9bf9f4Spatacca 	osprintf(os, ";\n");
6093f9bf9f4Spatacca 	osprintf(os, "  std::shared_ptr<%s_data> %s_data;\n",
6103f9bf9f4Spatacca 		callback_name.c_str(), callback_name.c_str());
6113f9bf9f4Spatacca 	osprintf(os, "  static inline ");
6123f9bf9f4Spatacca 	print_persistent_callback_prototype(method);
6133f9bf9f4Spatacca 	osprintf(os, ";\n");
6143f9bf9f4Spatacca 	osprintf(os, "  inline ");
6153f9bf9f4Spatacca 	print_persistent_callback_setter_prototype(method);
6163f9bf9f4Spatacca 	osprintf(os, ";\n");
6173f9bf9f4Spatacca }
6183f9bf9f4Spatacca 
6193f9bf9f4Spatacca /* Print declarations needed for the persistent callbacks of the class.
6203f9bf9f4Spatacca  *
6213f9bf9f4Spatacca  * In particular, if there are any persistent callbacks, then
6223f9bf9f4Spatacca  * print a private method for copying callback data from
6233f9bf9f4Spatacca  * one object to another,
6243f9bf9f4Spatacca  * private data for keeping track of the persistent callbacks and
6253f9bf9f4Spatacca  * public methods for setting the persistent callbacks.
6263f9bf9f4Spatacca  */
print_persistent_callbacks()6273f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_persistent_callbacks()
6283f9bf9f4Spatacca {
6293f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
6303f9bf9f4Spatacca 
6313f9bf9f4Spatacca 	if (!clazz.has_persistent_callbacks())
6323f9bf9f4Spatacca 		return;
6333f9bf9f4Spatacca 
6343f9bf9f4Spatacca 	osprintf(os, "private:\n");
6353f9bf9f4Spatacca 	osprintf(os, "  inline %s &copy_callbacks(const %s &obj);\n",
6363f9bf9f4Spatacca 		cppname, cppname);
6373f9bf9f4Spatacca 	for (const auto &callback : clazz.persistent_callbacks)
6383f9bf9f4Spatacca 		print_persistent_callback_data(callback);
6393f9bf9f4Spatacca 
6403f9bf9f4Spatacca 	osprintf(os, "public:\n");
6413f9bf9f4Spatacca 	for (const auto &callback : clazz.persistent_callbacks)
6423f9bf9f4Spatacca 		print_method(Method(clazz, callback));
6433f9bf9f4Spatacca }
6443f9bf9f4Spatacca 
6453f9bf9f4Spatacca /* Print a declaration for the "get" method "fd",
6463f9bf9f4Spatacca  * using a name that includes the "get_" prefix.
6473f9bf9f4Spatacca  */
print_get_method(FunctionDecl * fd)6483f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_get_method(FunctionDecl *fd)
6493f9bf9f4Spatacca {
6503f9bf9f4Spatacca 	string base = clazz.base_method_name(fd);
6513f9bf9f4Spatacca 
6523f9bf9f4Spatacca 	print_method(Method(clazz, fd, base));
6533f9bf9f4Spatacca }
6543f9bf9f4Spatacca 
6553f9bf9f4Spatacca /* Print implementations for class "clazz" to "os".
6563f9bf9f4Spatacca  */
print_class_impl(ostream & os,const isl_class & clazz)6573f9bf9f4Spatacca void plain_cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
6583f9bf9f4Spatacca {
6593f9bf9f4Spatacca 	impl_printer printer(os, clazz, *this);
6603f9bf9f4Spatacca 	const char *cppname = printer.cppstring.c_str();
6613f9bf9f4Spatacca 
6623f9bf9f4Spatacca 	osprintf(os, "// implementations for isl::%s", cppname);
6633f9bf9f4Spatacca 
6643f9bf9f4Spatacca 	printer.print_class_factory();
6653f9bf9f4Spatacca 	printer.print_protected_constructors();
666*a749e09eSMichael Kruse 	printer.print_public_methods();
6673f9bf9f4Spatacca 	printer.print_stream_insertion();
6683f9bf9f4Spatacca }
6693f9bf9f4Spatacca 
6703f9bf9f4Spatacca /* Print code for throwing an exception corresponding to the last error
6713f9bf9f4Spatacca  * that occurred on "saved_ctx".
6723f9bf9f4Spatacca  * This assumes that a valid isl::ctx is available in the "saved_ctx" variable,
6733f9bf9f4Spatacca  * e.g., through a prior call to print_save_ctx.
6743f9bf9f4Spatacca  */
print_throw_last_error(ostream & os)6753f9bf9f4Spatacca static void print_throw_last_error(ostream &os)
6763f9bf9f4Spatacca {
6773f9bf9f4Spatacca 	osprintf(os, "    exception::throw_last_error(saved_ctx);\n");
6783f9bf9f4Spatacca }
6793f9bf9f4Spatacca 
6803f9bf9f4Spatacca /* Print code with the given indentation
6813f9bf9f4Spatacca  * for throwing an exception_invalid with the given message.
6823f9bf9f4Spatacca  */
print_throw_invalid(ostream & os,int indent,const char * msg)6833f9bf9f4Spatacca static void print_throw_invalid(ostream &os, int indent, const char *msg)
6843f9bf9f4Spatacca {
6853f9bf9f4Spatacca 	osprintf(os, indent,
6863f9bf9f4Spatacca 		"exception::throw_invalid(\"%s\", __FILE__, __LINE__);\n", msg);
6873f9bf9f4Spatacca }
6883f9bf9f4Spatacca 
6893f9bf9f4Spatacca /* Print code for throwing an exception on NULL input.
6903f9bf9f4Spatacca  */
print_throw_NULL_input(ostream & os)6913f9bf9f4Spatacca static void print_throw_NULL_input(ostream &os)
6923f9bf9f4Spatacca {
6933f9bf9f4Spatacca 	print_throw_invalid(os, 4, "NULL input");
6943f9bf9f4Spatacca }
6953f9bf9f4Spatacca 
6963f9bf9f4Spatacca /* Print code with the given indentation
6973f9bf9f4Spatacca  * for acting on an invalid error with message "msg".
6983f9bf9f4Spatacca  * In particular, throw an exception_invalid.
6993f9bf9f4Spatacca  * In the checked C++ bindings, isl_die is called instead with the code
7003f9bf9f4Spatacca  * in "checked_code".
7013f9bf9f4Spatacca  */
print_invalid(ostream & os,int indent,const char * msg,const char * checked_code)7023f9bf9f4Spatacca void plain_cpp_generator::print_invalid(ostream &os, int indent,
7033f9bf9f4Spatacca 	const char *msg, const char *checked_code)
7043f9bf9f4Spatacca {
7053f9bf9f4Spatacca 	if (checked)
7063f9bf9f4Spatacca 		osprintf(os, indent,
7073f9bf9f4Spatacca 			"isl_die(ctx().get(), isl_error_invalid, "
7083f9bf9f4Spatacca 			"\"%s\", %s);\n", msg, checked_code);
7093f9bf9f4Spatacca 	else
7103f9bf9f4Spatacca 		print_throw_invalid(os, indent, msg);
7113f9bf9f4Spatacca }
7123f9bf9f4Spatacca 
7133f9bf9f4Spatacca /* Print an operator for inserting objects of the class
7143f9bf9f4Spatacca  * into an output stream.
7153f9bf9f4Spatacca  *
7163f9bf9f4Spatacca  * Unless checked C++ bindings are being generated,
7173f9bf9f4Spatacca  * the operator requires its argument to be non-NULL.
7183f9bf9f4Spatacca  * An exception is thrown if anything went wrong during the printing.
7193f9bf9f4Spatacca  * During this printing, isl is made not to print any error message
7203f9bf9f4Spatacca  * because the error message is included in the exception.
7213f9bf9f4Spatacca  *
7223f9bf9f4Spatacca  * If checked C++ bindings are being generated and anything went wrong,
7233f9bf9f4Spatacca  * then record this failure in the output stream.
7243f9bf9f4Spatacca  */
print_stream_insertion()7253f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_stream_insertion()
7263f9bf9f4Spatacca {
7273f9bf9f4Spatacca 	const char *name = clazz.name.c_str();
7283f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
7293f9bf9f4Spatacca 
7303f9bf9f4Spatacca 	if (!clazz.fn_to_str)
7313f9bf9f4Spatacca 		return;
7323f9bf9f4Spatacca 
7333f9bf9f4Spatacca 	osprintf(os, "\n");
7343f9bf9f4Spatacca 	osprintf(os, "inline std::ostream &operator<<(std::ostream &os, ");
7353f9bf9f4Spatacca 	osprintf(os, "const %s &obj)\n", cppname);
7363f9bf9f4Spatacca 	osprintf(os, "{\n");
7373f9bf9f4Spatacca 	print_check_ptr_start("obj.get()");
7383f9bf9f4Spatacca 	osprintf(os, "  char *str = %s_to_str(obj.get());\n", name);
7393f9bf9f4Spatacca 	print_check_ptr_end("str");
7403f9bf9f4Spatacca 	if (generator.checked) {
7413f9bf9f4Spatacca 		osprintf(os, "  if (!str) {\n");
7423f9bf9f4Spatacca 		osprintf(os, "    os.setstate(std::ios_base::badbit);\n");
7433f9bf9f4Spatacca 		osprintf(os, "    return os;\n");
7443f9bf9f4Spatacca 		osprintf(os, "  }\n");
7453f9bf9f4Spatacca 	}
7463f9bf9f4Spatacca 	osprintf(os, "  os << str;\n");
7473f9bf9f4Spatacca 	osprintf(os, "  free(str);\n");
7483f9bf9f4Spatacca 	osprintf(os, "  return os;\n");
7493f9bf9f4Spatacca 	osprintf(os, "}\n");
7503f9bf9f4Spatacca }
7513f9bf9f4Spatacca 
7523f9bf9f4Spatacca /* Print code that checks that "ptr" is not NULL at input.
7533f9bf9f4Spatacca  *
7543f9bf9f4Spatacca  * Omit the check if checked C++ bindings are being generated.
7553f9bf9f4Spatacca  */
print_check_ptr(const char * ptr)7563f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_check_ptr(const char *ptr)
7573f9bf9f4Spatacca {
7583f9bf9f4Spatacca 	if (generator.checked)
7593f9bf9f4Spatacca 		return;
7603f9bf9f4Spatacca 
7613f9bf9f4Spatacca 	osprintf(os, "  if (!%s)\n", ptr);
7623f9bf9f4Spatacca 	print_throw_NULL_input(os);
7633f9bf9f4Spatacca }
7643f9bf9f4Spatacca 
7653f9bf9f4Spatacca /* Print code that checks that "ptr" is not NULL at input and
7663f9bf9f4Spatacca  * that saves a copy of the isl_ctx of "ptr" for a later check.
7673f9bf9f4Spatacca  *
7683f9bf9f4Spatacca  * Omit the check if checked C++ bindings are being generated.
7693f9bf9f4Spatacca  */
print_check_ptr_start(const char * ptr)7703f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_check_ptr_start(const char *ptr)
7713f9bf9f4Spatacca {
7723f9bf9f4Spatacca 	if (generator.checked)
7733f9bf9f4Spatacca 		return;
7743f9bf9f4Spatacca 
7753f9bf9f4Spatacca 	print_check_ptr(ptr);
776*a749e09eSMichael Kruse 	print_save_ctx(clazz.name + "_get_ctx(" + ptr + ")");
7773f9bf9f4Spatacca 	print_on_error_continue();
7783f9bf9f4Spatacca }
7793f9bf9f4Spatacca 
7803f9bf9f4Spatacca /* Print code that checks that "ptr" is not NULL at the end.
7813f9bf9f4Spatacca  * A copy of the isl_ctx is expected to have been saved by
7823f9bf9f4Spatacca  * code generated by print_check_ptr_start.
7833f9bf9f4Spatacca  *
7843f9bf9f4Spatacca  * Omit the check if checked C++ bindings are being generated.
7853f9bf9f4Spatacca  */
print_check_ptr_end(const char * ptr)7863f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_check_ptr_end(const char *ptr)
7873f9bf9f4Spatacca {
7883f9bf9f4Spatacca 	if (generator.checked)
7893f9bf9f4Spatacca 		return;
7903f9bf9f4Spatacca 
7913f9bf9f4Spatacca 	osprintf(os, "  if (!%s)\n", ptr);
7923f9bf9f4Spatacca 	print_throw_last_error(os);
7933f9bf9f4Spatacca }
7943f9bf9f4Spatacca 
7953f9bf9f4Spatacca /* Print implementation of global factory functions.
7963f9bf9f4Spatacca  *
7973f9bf9f4Spatacca  * Each class has two global factory functions:
7983f9bf9f4Spatacca  *
7993f9bf9f4Spatacca  * 	set manage(__isl_take isl_set *ptr);
8003f9bf9f4Spatacca  * 	set manage_copy(__isl_keep isl_set *ptr);
8013f9bf9f4Spatacca  *
8023f9bf9f4Spatacca  * Unless checked C++ bindings are being generated,
8033f9bf9f4Spatacca  * both functions require the argument to be non-NULL.
8043f9bf9f4Spatacca  * An exception is thrown if anything went wrong during the copying
8053f9bf9f4Spatacca  * in manage_copy.
8063f9bf9f4Spatacca  * During the copying, isl is made not to print any error message
8073f9bf9f4Spatacca  * because the error message is included in the exception.
8083f9bf9f4Spatacca  *
8093f9bf9f4Spatacca  * For a subclass based on a type function, no factory functions
8103f9bf9f4Spatacca  * are introduced because they share the C object type with
8113f9bf9f4Spatacca  * the superclass.
8123f9bf9f4Spatacca  */
print_class_factory()8133f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_class_factory()
8143f9bf9f4Spatacca {
8153f9bf9f4Spatacca 	const char *name = clazz.name.c_str();
8163f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
8173f9bf9f4Spatacca 
8183f9bf9f4Spatacca 	if (clazz.is_type_subclass())
8193f9bf9f4Spatacca 		return;
8203f9bf9f4Spatacca 
8213f9bf9f4Spatacca 	osprintf(os, "\n");
8223f9bf9f4Spatacca 	osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
8233f9bf9f4Spatacca 	print_check_ptr("ptr");
8243f9bf9f4Spatacca 	osprintf(os, "  return %s(ptr);\n", cppname);
8253f9bf9f4Spatacca 	osprintf(os, "}\n");
8263f9bf9f4Spatacca 
8273f9bf9f4Spatacca 	osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
8283f9bf9f4Spatacca 		name);
8293f9bf9f4Spatacca 	print_check_ptr_start("ptr");
8303f9bf9f4Spatacca 	osprintf(os, "  ptr = %s_copy(ptr);\n", name);
8313f9bf9f4Spatacca 	print_check_ptr_end("ptr");
8323f9bf9f4Spatacca 	osprintf(os, "  return %s(ptr);\n", cppname);
8333f9bf9f4Spatacca 	osprintf(os, "}\n");
8343f9bf9f4Spatacca }
8353f9bf9f4Spatacca 
8363f9bf9f4Spatacca /* Print implementations of protected constructors.
8373f9bf9f4Spatacca  *
8383f9bf9f4Spatacca  * The pointer to the isl object is either initialized directly or
8393f9bf9f4Spatacca  * through the (immediate) superclass.
8403f9bf9f4Spatacca  */
print_protected_constructors()8413f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_protected_constructors()
8423f9bf9f4Spatacca {
8433f9bf9f4Spatacca 	const char *name = clazz.name.c_str();
8443f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
8453f9bf9f4Spatacca 	bool subclass = clazz.is_type_subclass();
8463f9bf9f4Spatacca 
8473f9bf9f4Spatacca 	osprintf(os, "\n");
8483f9bf9f4Spatacca 	osprintf(os, "%s::%s(__isl_take %s *ptr)\n", cppname, cppname, name);
8493f9bf9f4Spatacca 	if (subclass)
8503f9bf9f4Spatacca 		osprintf(os, "    : %s(ptr) {}\n",
8513f9bf9f4Spatacca 			type2cpp(clazz.superclass_name).c_str());
8523f9bf9f4Spatacca 	else
8533f9bf9f4Spatacca 		osprintf(os, "    : ptr(ptr) {}\n");
8543f9bf9f4Spatacca }
8553f9bf9f4Spatacca 
8563f9bf9f4Spatacca /* Print implementations of public constructors.
8573f9bf9f4Spatacca  *
8583f9bf9f4Spatacca  * The pointer to the isl object is either initialized directly or
8593f9bf9f4Spatacca  * through the (immediate) superclass.
8603f9bf9f4Spatacca  *
8613f9bf9f4Spatacca  * If the class has any persistent callbacks, then copy them
8623f9bf9f4Spatacca  * from the original object in the copy constructor.
8633f9bf9f4Spatacca  * If the class is a subclass, then the persistent callbacks
8643f9bf9f4Spatacca  * are assumed to be copied by the copy constructor of the superclass.
8653f9bf9f4Spatacca  *
8663f9bf9f4Spatacca  * Throw an exception from the copy constructor if anything went wrong
8673f9bf9f4Spatacca  * during the copying or if the input is NULL, if any copying is performed.
8683f9bf9f4Spatacca  * During the copying, isl is made not to print any error message
8693f9bf9f4Spatacca  * because the error message is included in the exception.
8703f9bf9f4Spatacca  * No exceptions are thrown if checked C++ bindings
8713f9bf9f4Spatacca  * are being generated,
8723f9bf9f4Spatacca  */
print_public_constructors()8733f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_public_constructors()
8743f9bf9f4Spatacca {
8753f9bf9f4Spatacca 	std::string super;
8763f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
8773f9bf9f4Spatacca 	bool subclass = clazz.is_type_subclass();
8783f9bf9f4Spatacca 
8793f9bf9f4Spatacca 	osprintf(os, "\n");
8803f9bf9f4Spatacca 	if (subclass)
8813f9bf9f4Spatacca 		super = type2cpp(clazz.superclass_name);
8823f9bf9f4Spatacca 	osprintf(os, "%s::%s()\n", cppname, cppname);
8833f9bf9f4Spatacca 	if (subclass)
8843f9bf9f4Spatacca 		osprintf(os, "    : %s() {}\n\n", super.c_str());
8853f9bf9f4Spatacca 	else
8863f9bf9f4Spatacca 		osprintf(os, "    : ptr(nullptr) {}\n\n");
8873f9bf9f4Spatacca 	osprintf(os, "%s::%s(const %s &obj)\n", cppname, cppname, cppname);
8883f9bf9f4Spatacca 	if (subclass)
8893f9bf9f4Spatacca 		osprintf(os, "    : %s(obj)\n", super.c_str());
8903f9bf9f4Spatacca 	else
8913f9bf9f4Spatacca 		osprintf(os, "    : ptr(nullptr)\n");
8923f9bf9f4Spatacca 	osprintf(os, "{\n");
8933f9bf9f4Spatacca 	if (!subclass) {
8943f9bf9f4Spatacca 		print_check_ptr_start("obj.ptr");
8953f9bf9f4Spatacca 		osprintf(os, "  ptr = obj.copy();\n");
8963f9bf9f4Spatacca 		if (clazz.has_persistent_callbacks())
8973f9bf9f4Spatacca 			osprintf(os, "  copy_callbacks(obj);\n");
8983f9bf9f4Spatacca 		print_check_ptr_end("ptr");
8993f9bf9f4Spatacca 	}
9003f9bf9f4Spatacca 	osprintf(os, "}\n");
9013f9bf9f4Spatacca }
9023f9bf9f4Spatacca 
9033f9bf9f4Spatacca /* Print definition for "method",
9043f9bf9f4Spatacca  * without any automatic type conversions.
9053f9bf9f4Spatacca  *
9063f9bf9f4Spatacca  * This method distinguishes three kinds of methods: member methods, static
9073f9bf9f4Spatacca  * methods, and constructors.
9083f9bf9f4Spatacca  *
9093f9bf9f4Spatacca  * Member methods and static methods return a newly managed
9103f9bf9f4Spatacca  * isl C++ object.
9113f9bf9f4Spatacca  *
9123f9bf9f4Spatacca  * Constructors create a new object from a given set of input parameters. They
9133f9bf9f4Spatacca  * do not return a value, but instead update the pointer stored inside the
9143f9bf9f4Spatacca  * newly created object.
9153f9bf9f4Spatacca  *
9163f9bf9f4Spatacca  * Unless checked C++ bindings are being generated,
9173f9bf9f4Spatacca  * the inputs of the method are first checked for being valid isl objects and
9183f9bf9f4Spatacca  * a copy of the associated isl::ctx is saved (if needed).
9193f9bf9f4Spatacca  * If any failure occurs, either during the check for the inputs or
9203f9bf9f4Spatacca  * during the isl function call, an exception is thrown.
9213f9bf9f4Spatacca  * During the function call, isl is made not to print any error message
9223f9bf9f4Spatacca  * because the error message is included in the exception.
9233f9bf9f4Spatacca  */
print_method(const Method & method)9243f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_method(const Method &method)
9253f9bf9f4Spatacca {
9263f9bf9f4Spatacca 	string methodname = method.fd->getName().str();
9273f9bf9f4Spatacca 	int num_params = method.c_num_params();
9283f9bf9f4Spatacca 
9293f9bf9f4Spatacca 	osprintf(os, "\n");
9303f9bf9f4Spatacca 	print_full_method_header(method);
9313f9bf9f4Spatacca 	osprintf(os, "{\n");
9323f9bf9f4Spatacca 	print_argument_validity_check(method);
9333f9bf9f4Spatacca 	print_save_ctx(method);
9343f9bf9f4Spatacca 	print_on_error_continue();
9353f9bf9f4Spatacca 
936*a749e09eSMichael Kruse 	for (const auto &callback : method.callbacks)
937*a749e09eSMichael Kruse 		print_callback_local(callback);
9383f9bf9f4Spatacca 
9393f9bf9f4Spatacca 	osprintf(os, "  auto res = %s", methodname.c_str());
9403f9bf9f4Spatacca 
941*a749e09eSMichael Kruse 	method.print_fd_arg_list(os, 0, num_params, [&] (int i, int arg) {
9423f9bf9f4Spatacca 		method.print_param_use(os, i);
9433f9bf9f4Spatacca 	});
9443f9bf9f4Spatacca 	osprintf(os, ";\n");
9453f9bf9f4Spatacca 
9463f9bf9f4Spatacca 	print_exceptional_execution_check(method);
9473f9bf9f4Spatacca 	if (method.kind == Method::Kind::constructor) {
9483f9bf9f4Spatacca 		osprintf(os, "  ptr = res;\n");
9493f9bf9f4Spatacca 	} else {
9503f9bf9f4Spatacca 		print_method_return(method);
9513f9bf9f4Spatacca 	}
9523f9bf9f4Spatacca 
9533f9bf9f4Spatacca 	osprintf(os, "}\n");
9543f9bf9f4Spatacca }
9553f9bf9f4Spatacca 
9563f9bf9f4Spatacca /* Convert argument of type "src" to "dst", with a name specified by "dst".
9573f9bf9f4Spatacca  *
9583f9bf9f4Spatacca  * If "src" is the same as "dst", then no argument conversion is needed.
9593f9bf9f4Spatacca  *
9603f9bf9f4Spatacca  * Otherwise, call the conversion function
9613f9bf9f4Spatacca  * with as arguments the isl_ctx of the object and the argument name,
9623f9bf9f4Spatacca  * or simply the argument name if the source type is an isl type.
9633f9bf9f4Spatacca  * This means this isl_ctx should be available.
9643f9bf9f4Spatacca  */
print_arg_conversion(ParmVarDecl * dst,ParmVarDecl * src)9653f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_arg_conversion(ParmVarDecl *dst,
9663f9bf9f4Spatacca 	ParmVarDecl *src)
9673f9bf9f4Spatacca {
9683f9bf9f4Spatacca 	std::string name = dst->getName().str();
9693f9bf9f4Spatacca 	QualType type = dst->getOriginalType();
9703f9bf9f4Spatacca 	string cpptype = generator.param2cpp(type);
9713f9bf9f4Spatacca 
9723f9bf9f4Spatacca 	if (dst == src)
9733f9bf9f4Spatacca 		os << name;
9743f9bf9f4Spatacca 	else if (is_isl_type(src->getOriginalType()))
9753f9bf9f4Spatacca 		os << cpptype << "(" << name << ")";
9763f9bf9f4Spatacca 	else
9773f9bf9f4Spatacca 		os << cpptype << "(ctx(), " << name << ")";
9783f9bf9f4Spatacca }
9793f9bf9f4Spatacca 
9803f9bf9f4Spatacca /* Print a definition for "method",
9813f9bf9f4Spatacca  * where "this" or at least one of the argument types needs to be converted.
9823f9bf9f4Spatacca  *
9833f9bf9f4Spatacca  * "method" is assumed to be a member method.
9843f9bf9f4Spatacca  *
9853f9bf9f4Spatacca  * The generated method performs the required conversion(s) and
9863f9bf9f4Spatacca  * calls the method generated without conversions.
9873f9bf9f4Spatacca  *
9883f9bf9f4Spatacca  * Perform a conversion from the argument in the method declaration
9893f9bf9f4Spatacca  * (as specified by Method::get_param) to the argument of the C function,
9903f9bf9f4Spatacca  * if needed.
9913f9bf9f4Spatacca  * Such a conversion may require the isl_ctx to be available.
9923f9bf9f4Spatacca  * In order to be able to use this isl_ctx, the current object needs
9933f9bf9f4Spatacca  * to valid.  The validity of other arguments is checked
9943f9bf9f4Spatacca  * by the called method.
9953f9bf9f4Spatacca  */
print_method(const ConversionMethod & method)9963f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_method(
9973f9bf9f4Spatacca 	const ConversionMethod &method)
9983f9bf9f4Spatacca {
9993f9bf9f4Spatacca 	if (method.kind != Method::Kind::member_method)
10003f9bf9f4Spatacca 		die("Automatic conversion currently only supported "
10013f9bf9f4Spatacca 		    "for object methods");
10023f9bf9f4Spatacca 
10033f9bf9f4Spatacca 	osprintf(os, "\n");
10043f9bf9f4Spatacca 	print_full_method_header(method);
10053f9bf9f4Spatacca 	osprintf(os, "{\n");
10063f9bf9f4Spatacca 	print_check_ptr("ptr");
10073f9bf9f4Spatacca 	osprintf(os, "  return ");
10083f9bf9f4Spatacca 	method.print_call(os, generator.isl_namespace());
1009*a749e09eSMichael Kruse 	method.print_cpp_arg_list(os, [&] (int i, int arg) {
10103f9bf9f4Spatacca 		ParmVarDecl *param = method.fd->getParamDecl(i);
10113f9bf9f4Spatacca 
10123f9bf9f4Spatacca 		print_arg_conversion(param, method.get_param(i));
10133f9bf9f4Spatacca 	});
10143f9bf9f4Spatacca 	osprintf(os, ";\n");
10153f9bf9f4Spatacca 	osprintf(os, "}\n");
10163f9bf9f4Spatacca }
10173f9bf9f4Spatacca 
1018*a749e09eSMichael Kruse /* Print a definition for a constructor for the "id" class
1019*a749e09eSMichael Kruse  * that takes a user object.
1020*a749e09eSMichael Kruse  *
1021*a749e09eSMichael Kruse  * The user object is taken as a std::any and copied into
1022*a749e09eSMichael Kruse  * a new std::any object on the heap.
1023*a749e09eSMichael Kruse  * A pointer to this heap object is stored in the isl_id and
1024*a749e09eSMichael Kruse  * is scheduled to be freed when the reference count of the isl_id
1025*a749e09eSMichael Kruse  * drops to zero.
1026*a749e09eSMichael Kruse  * If the allocation of the isl_id fails, then the heap object
1027*a749e09eSMichael Kruse  * will not be freed automatically, so it needs to be freed manually.
1028*a749e09eSMichael Kruse  *
1029*a749e09eSMichael Kruse  * Unless checked C++ bindings are being generated,
1030*a749e09eSMichael Kruse  * the ctx argument is copied into the save_ctx variable
1031*a749e09eSMichael Kruse  * for use by print_throw_last_error, which throws an exception
1032*a749e09eSMichael Kruse  * if the construction fails.
1033*a749e09eSMichael Kruse  * During the function call, isl is made not to print any error message
1034*a749e09eSMichael Kruse  * because the error message is included in the exception.
1035*a749e09eSMichael Kruse  */
print_id_constructor_user()1036*a749e09eSMichael Kruse void plain_cpp_generator::impl_printer::print_id_constructor_user()
1037*a749e09eSMichael Kruse {
1038*a749e09eSMichael Kruse 	print_id_constructor_user_header();
1039*a749e09eSMichael Kruse 	os << "{\n";
1040*a749e09eSMichael Kruse 	if (!generator.checked) {
1041*a749e09eSMichael Kruse 		print_save_ctx("ctx");
1042*a749e09eSMichael Kruse 		print_on_error_continue();
1043*a749e09eSMichael Kruse 	}
1044*a749e09eSMichael Kruse 	os << "  std::any *p = new std::any(any);\n";
1045*a749e09eSMichael Kruse 	os << "  auto res = isl_id_alloc(ctx.get(), str.c_str(), p);\n";
1046*a749e09eSMichael Kruse 	os << "  res = isl_id_set_free_user(res, &ctx::free_user);\n";
1047*a749e09eSMichael Kruse 	os << "  if (!res) {\n";
1048*a749e09eSMichael Kruse 	os << "    delete p;\n";
1049*a749e09eSMichael Kruse 	if (!generator.checked)
1050*a749e09eSMichael Kruse 		print_throw_last_error(os);
1051*a749e09eSMichael Kruse 	os << "  }\n";
1052*a749e09eSMichael Kruse 	os << "  ptr = res;\n";
1053*a749e09eSMichael Kruse 	os << "}\n";
1054*a749e09eSMichael Kruse }
1055*a749e09eSMichael Kruse 
1056*a749e09eSMichael Kruse /* Print a definition for an "id" method
1057*a749e09eSMichael Kruse  * for retrieving the user object associated to the identifier.
1058*a749e09eSMichael Kruse  * If "optional" is set, the method returns a std::optional user object.
1059*a749e09eSMichael Kruse  * The returned object is of a type specified by template parameter T.
1060*a749e09eSMichael Kruse  *
1061*a749e09eSMichael Kruse  * The isl_id needs to have been created by the constructor generated
1062*a749e09eSMichael Kruse  * by print_id_constructor_user.  That is, it needs to have a user pointer and
1063*a749e09eSMichael Kruse  * it needs to have its free_user callback set to &ctx::free_user.
1064*a749e09eSMichael Kruse  * The object stored in the std::any also needs to be of the required type.
1065*a749e09eSMichael Kruse  *
1066*a749e09eSMichael Kruse  * If "optional" is set, return a std::nullopt if any of the checks fail.
1067*a749e09eSMichael Kruse  * Otherwise, throw an exception_invalid (or call isl_die and
1068*a749e09eSMichael Kruse  * return a default T in the checked C++ bindings).
1069*a749e09eSMichael Kruse  */
print_id_user(bool optional)1070*a749e09eSMichael Kruse void plain_cpp_generator::impl_printer::print_id_user(bool optional)
1071*a749e09eSMichael Kruse {
1072*a749e09eSMichael Kruse 	auto fail = [&] (const char *msg) {
1073*a749e09eSMichael Kruse 		if (optional)
1074*a749e09eSMichael Kruse 			os << "    return std::nullopt;\n";
1075*a749e09eSMichael Kruse 		else
1076*a749e09eSMichael Kruse 			generator.print_invalid(os, 4, msg, "return T()");
1077*a749e09eSMichael Kruse 	};
1078*a749e09eSMichael Kruse 	os << "\n";
1079*a749e09eSMichael Kruse 	print_id_user_header(optional);
1080*a749e09eSMichael Kruse 	os << "{\n";
1081*a749e09eSMichael Kruse 	print_check_ptr("ptr");
1082*a749e09eSMichael Kruse 	os << "  std::any *p = (std::any *) isl_id_get_user(ptr);\n";
1083*a749e09eSMichael Kruse 	os << "  if (!p)\n";
1084*a749e09eSMichael Kruse 	fail("no user pointer");
1085*a749e09eSMichael Kruse 	os << "  if (isl_id_get_free_user(ptr) != &ctx::free_user)\n";
1086*a749e09eSMichael Kruse 	fail("user pointer not attached by C++ interface");
1087*a749e09eSMichael Kruse 	os << "  T *res = std::any_cast<T>(p);\n";
1088*a749e09eSMichael Kruse 	os << "  if (!res)\n";
1089*a749e09eSMichael Kruse 	fail("user pointer not of given type");
1090*a749e09eSMichael Kruse 	os << "  return *res;\n";
1091*a749e09eSMichael Kruse 	os << "}\n";
1092*a749e09eSMichael Kruse }
1093*a749e09eSMichael Kruse 
10943f9bf9f4Spatacca /* Print implementation of copy assignment operator.
10953f9bf9f4Spatacca  *
10963f9bf9f4Spatacca  * If the class has any persistent callbacks, then copy them
10973f9bf9f4Spatacca  * from the original object.
10983f9bf9f4Spatacca  */
print_copy_assignment()10993f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_copy_assignment()
11003f9bf9f4Spatacca {
11013f9bf9f4Spatacca 	const char *name = clazz.name.c_str();
11023f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
11033f9bf9f4Spatacca 
11043f9bf9f4Spatacca 	osprintf(os, "\n");
11053f9bf9f4Spatacca 	osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname,
11063f9bf9f4Spatacca 		 cppname, cppname);
11073f9bf9f4Spatacca 	osprintf(os, "  std::swap(this->ptr, obj.ptr);\n", name);
11083f9bf9f4Spatacca 	if (clazz.has_persistent_callbacks())
11093f9bf9f4Spatacca 		osprintf(os, "  copy_callbacks(obj);\n");
11103f9bf9f4Spatacca 	osprintf(os, "  return *this;\n");
11113f9bf9f4Spatacca 	osprintf(os, "}\n");
11123f9bf9f4Spatacca }
11133f9bf9f4Spatacca 
11143f9bf9f4Spatacca /* Print implementation of destructor.
11153f9bf9f4Spatacca  *
11163f9bf9f4Spatacca  * No explicit destructor is needed for type based subclasses.
11173f9bf9f4Spatacca  */
print_destructor()11183f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_destructor()
11193f9bf9f4Spatacca {
11203f9bf9f4Spatacca 	const char *name = clazz.name.c_str();
11213f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
11223f9bf9f4Spatacca 
11233f9bf9f4Spatacca 	if (clazz.is_type_subclass())
11243f9bf9f4Spatacca 		return;
11253f9bf9f4Spatacca 
11263f9bf9f4Spatacca 	osprintf(os, "\n");
11273f9bf9f4Spatacca 	osprintf(os, "%s::~%s() {\n", cppname, cppname);
11283f9bf9f4Spatacca 	osprintf(os, "  if (ptr)\n");
11293f9bf9f4Spatacca 	osprintf(os, "    %s_free(ptr);\n", name);
11303f9bf9f4Spatacca 	osprintf(os, "}\n");
11313f9bf9f4Spatacca }
11323f9bf9f4Spatacca 
11333f9bf9f4Spatacca /* Print a check that the persistent callback corresponding to "fd"
11343f9bf9f4Spatacca  * is not set, throwing an exception (or printing an error message
11353f9bf9f4Spatacca  * and returning nullptr) if it is set.
11363f9bf9f4Spatacca  */
print_check_no_persistent_callback(ostream & os,const isl_class & clazz,FunctionDecl * fd)11373f9bf9f4Spatacca void plain_cpp_generator::print_check_no_persistent_callback(ostream &os,
11383f9bf9f4Spatacca 	const isl_class &clazz, FunctionDecl *fd)
11393f9bf9f4Spatacca {
11403f9bf9f4Spatacca 	string callback_name = clazz.persistent_callback_name(fd);
11413f9bf9f4Spatacca 
11423f9bf9f4Spatacca 	osprintf(os, "  if (%s_data)\n", callback_name.c_str());
11433f9bf9f4Spatacca 	print_invalid(os, 4, "cannot release object with persistent callbacks",
11443f9bf9f4Spatacca 			    "return nullptr");
11453f9bf9f4Spatacca }
11463f9bf9f4Spatacca 
11473f9bf9f4Spatacca /* Print implementation of ptr() functions.
11483f9bf9f4Spatacca  * Since type based subclasses share the pointer with their superclass,
11493f9bf9f4Spatacca  * they can also reuse these functions from the superclass.
11503f9bf9f4Spatacca  *
11513f9bf9f4Spatacca  * If an object has persistent callbacks set, then the underlying
11523f9bf9f4Spatacca  * C object pointer cannot be released because it references data
11533f9bf9f4Spatacca  * in the C++ object.
11543f9bf9f4Spatacca  */
print_ptr()11553f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_ptr()
11563f9bf9f4Spatacca {
11573f9bf9f4Spatacca 	const char *name = clazz.name.c_str();
11583f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
11593f9bf9f4Spatacca 	set<FunctionDecl *>::const_iterator in;
11603f9bf9f4Spatacca 	const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
11613f9bf9f4Spatacca 
11623f9bf9f4Spatacca 	if (clazz.is_type_subclass())
11633f9bf9f4Spatacca 		return;
11643f9bf9f4Spatacca 
11653f9bf9f4Spatacca 	osprintf(os, "\n");
11663f9bf9f4Spatacca 	osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
11673f9bf9f4Spatacca 	osprintf(os, "  return %s_copy(ptr);\n", name);
11683f9bf9f4Spatacca 	osprintf(os, "}\n\n");
11693f9bf9f4Spatacca 	osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
11703f9bf9f4Spatacca 	osprintf(os, "  return ptr;\n");
11713f9bf9f4Spatacca 	osprintf(os, "}\n\n");
11723f9bf9f4Spatacca 	osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
11733f9bf9f4Spatacca 	for (in = callbacks.begin(); in != callbacks.end(); ++in)
11743f9bf9f4Spatacca 		generator.print_check_no_persistent_callback(os, clazz, *in);
11753f9bf9f4Spatacca 	osprintf(os, "  %s *tmp = ptr;\n", name);
11763f9bf9f4Spatacca 	osprintf(os, "  ptr = nullptr;\n");
11773f9bf9f4Spatacca 	osprintf(os, "  return tmp;\n");
11783f9bf9f4Spatacca 	osprintf(os, "}\n\n");
11793f9bf9f4Spatacca 	osprintf(os, "bool %s::is_null() const {\n", cppname);
11803f9bf9f4Spatacca 	osprintf(os, "  return ptr == nullptr;\n");
11813f9bf9f4Spatacca 	osprintf(os, "}\n");
11823f9bf9f4Spatacca }
11833f9bf9f4Spatacca 
11843f9bf9f4Spatacca /* Print implementations for the "as" and "isa" methods, if the printed class
11853f9bf9f4Spatacca  * is a superclass with a type function.
11863f9bf9f4Spatacca  *
11873f9bf9f4Spatacca  * "isa" checks whether an object is of a given subclass type.
11883f9bf9f4Spatacca  * "isa_type" does the same, but gets passed the value of the type field
11893f9bf9f4Spatacca  * of the subclass as a function argument and the type of this field
11903f9bf9f4Spatacca  * as a template argument.
11913f9bf9f4Spatacca  * "as" casts an object to a given subclass type, erroring out
11923f9bf9f4Spatacca  * if the object is not of the given type.
11933f9bf9f4Spatacca  *
11943f9bf9f4Spatacca  * If the input is an invalid object, then these methods raise
11953f9bf9f4Spatacca  * an exception.
11963f9bf9f4Spatacca  * If checked bindings are being generated,
11973f9bf9f4Spatacca  * then an invalid boolean or object is returned instead.
11983f9bf9f4Spatacca  */
print_downcast()11993f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_downcast()
12003f9bf9f4Spatacca {
12013f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
12023f9bf9f4Spatacca 
12033f9bf9f4Spatacca 	if (!clazz.fn_type)
12043f9bf9f4Spatacca 		return;
12053f9bf9f4Spatacca 
12063f9bf9f4Spatacca 	osprintf(os, "\n");
12073f9bf9f4Spatacca 	osprintf(os, "template <typename T, typename>\n");
12083f9bf9f4Spatacca 	osprintf(os, "%s %s::isa_type(T subtype) const\n",
12093f9bf9f4Spatacca 		generator.isl_bool2cpp().c_str(), cppname);
12103f9bf9f4Spatacca 	osprintf(os, "{\n");
12113f9bf9f4Spatacca 	osprintf(os, "  if (is_null())\n");
12123f9bf9f4Spatacca 	if (generator.checked)
12133f9bf9f4Spatacca 		osprintf(os, "    return boolean();\n");
12143f9bf9f4Spatacca 	else
12153f9bf9f4Spatacca 		print_throw_NULL_input(os);
12163f9bf9f4Spatacca 	osprintf(os, "  return %s(get()) == subtype;\n",
12173f9bf9f4Spatacca 		clazz.fn_type->getNameAsString().c_str());
12183f9bf9f4Spatacca 	osprintf(os, "}\n");
12193f9bf9f4Spatacca 
12203f9bf9f4Spatacca 	osprintf(os, "template <class T>\n");
12213f9bf9f4Spatacca 	osprintf(os, "%s %s::isa() const\n",
12223f9bf9f4Spatacca 		generator.isl_bool2cpp().c_str(), cppname);
12233f9bf9f4Spatacca 	osprintf(os, "{\n");
12243f9bf9f4Spatacca 	osprintf(os, "  return isa_type<decltype(T::type)>(T::type);\n");
12253f9bf9f4Spatacca 	osprintf(os, "}\n");
12263f9bf9f4Spatacca 
12273f9bf9f4Spatacca 	osprintf(os, "template <class T>\n");
12283f9bf9f4Spatacca 	osprintf(os, "T %s::as() const\n", cppname);
12293f9bf9f4Spatacca 	osprintf(os, "{\n");
12303f9bf9f4Spatacca 	if (generator.checked)
12313f9bf9f4Spatacca 		osprintf(os, " if (isa<T>().is_false())\n");
12323f9bf9f4Spatacca 	else
12333f9bf9f4Spatacca 		osprintf(os, " if (!isa<T>())\n");
12343f9bf9f4Spatacca 	generator.print_invalid(os, 4, "not an object of the requested subtype",
12353f9bf9f4Spatacca 		    "return T()");
12363f9bf9f4Spatacca 	osprintf(os, "  return T(copy());\n");
12373f9bf9f4Spatacca 	osprintf(os, "}\n");
12383f9bf9f4Spatacca }
12393f9bf9f4Spatacca 
12403f9bf9f4Spatacca /* Print the implementation of the ctx method.
12413f9bf9f4Spatacca  */
print_ctx()12423f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_ctx()
12433f9bf9f4Spatacca {
12443f9bf9f4Spatacca 	const char *name = clazz.name.c_str();
12453f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
12463f9bf9f4Spatacca 	std::string ns = generator.isl_namespace();
12473f9bf9f4Spatacca 
12483f9bf9f4Spatacca 	osprintf(os, "\n");
12493f9bf9f4Spatacca 	osprintf(os, "%sctx %s::ctx() const {\n", ns.c_str(), cppname);
12503f9bf9f4Spatacca 	osprintf(os, "  return %sctx(%s_get_ctx(ptr));\n", ns.c_str(), name);
12513f9bf9f4Spatacca 	osprintf(os, "}\n");
12523f9bf9f4Spatacca }
12533f9bf9f4Spatacca 
1254*a749e09eSMichael Kruse /* Print a separator between groups of method definitions.
1255*a749e09eSMichael Kruse  *
1256*a749e09eSMichael Kruse  * No additional separator is required between method definitions.
1257*a749e09eSMichael Kruse  */
print_method_separator()1258*a749e09eSMichael Kruse void plain_cpp_generator::impl_printer::print_method_separator()
1259*a749e09eSMichael Kruse {
1260*a749e09eSMichael Kruse }
1261*a749e09eSMichael Kruse 
12623f9bf9f4Spatacca /* Print the implementations of the methods needed for the persistent callbacks
12633f9bf9f4Spatacca  * of the class.
12643f9bf9f4Spatacca  */
print_persistent_callbacks()12653f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_persistent_callbacks()
12663f9bf9f4Spatacca {
12673f9bf9f4Spatacca 	const char *cppname = cppstring.c_str();
12683f9bf9f4Spatacca 	string classname = type2cpp(clazz);
12693f9bf9f4Spatacca 
12703f9bf9f4Spatacca 	if (!clazz.has_persistent_callbacks())
12713f9bf9f4Spatacca 		return;
12723f9bf9f4Spatacca 
12733f9bf9f4Spatacca 	osprintf(os, "\n");
12743f9bf9f4Spatacca 	osprintf(os, "%s &%s::copy_callbacks(const %s &obj)\n",
12753f9bf9f4Spatacca 		cppname, classname.c_str(), cppname);
12763f9bf9f4Spatacca 	osprintf(os, "{\n");
12773f9bf9f4Spatacca 	for (const auto &callback : clazz.persistent_callbacks) {
12783f9bf9f4Spatacca 		string callback_name = clazz.persistent_callback_name(callback);
12793f9bf9f4Spatacca 
12803f9bf9f4Spatacca 		osprintf(os, "  %s_data = obj.%s_data;\n",
12813f9bf9f4Spatacca 			callback_name.c_str(), callback_name.c_str());
12823f9bf9f4Spatacca 	}
12833f9bf9f4Spatacca 	osprintf(os, "  return *this;\n");
12843f9bf9f4Spatacca 	osprintf(os, "}\n");
12853f9bf9f4Spatacca 
12863f9bf9f4Spatacca 	for (const auto &callback : clazz.persistent_callbacks)
12873f9bf9f4Spatacca 		print_set_persistent_callback(Method(clazz, callback));
12883f9bf9f4Spatacca }
12893f9bf9f4Spatacca 
12903f9bf9f4Spatacca /* Print a definition for the "get" method "fd" in class "clazz",
12913f9bf9f4Spatacca  * using a name that includes the "get_" prefix, to "os".
12923f9bf9f4Spatacca  *
12933f9bf9f4Spatacca  * This definition simply calls the variant without the "get_" prefix and
12943f9bf9f4Spatacca  * returns its result.
12953f9bf9f4Spatacca  * Note that static methods are not considered to be "get" methods.
12963f9bf9f4Spatacca  */
print_get_method(FunctionDecl * fd)12973f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_get_method(FunctionDecl *fd)
12983f9bf9f4Spatacca {
12993f9bf9f4Spatacca 	string get_name = clazz.base_method_name(fd);
13003f9bf9f4Spatacca 	string name = clazz.method_name(fd);
13013f9bf9f4Spatacca 	int num_params = fd->getNumParams();
13023f9bf9f4Spatacca 
13033f9bf9f4Spatacca 	osprintf(os, "\n");
13043f9bf9f4Spatacca 	print_full_method_header(Method(clazz, fd, get_name));
13053f9bf9f4Spatacca 	osprintf(os, "{\n");
13063f9bf9f4Spatacca 	osprintf(os, "  return %s(", name.c_str());
13073f9bf9f4Spatacca 	for (int i = 1; i < num_params; ++i) {
13083f9bf9f4Spatacca 		ParmVarDecl *param = fd->getParamDecl(i);
13093f9bf9f4Spatacca 
13103f9bf9f4Spatacca 		if (i != 1)
13113f9bf9f4Spatacca 			osprintf(os, ", ");
13123f9bf9f4Spatacca 		osprintf(os, "%s", param->getName().str().c_str());
13133f9bf9f4Spatacca 	}
13143f9bf9f4Spatacca 	osprintf(os, ");\n");
13153f9bf9f4Spatacca 	osprintf(os, "}\n");
13163f9bf9f4Spatacca }
13173f9bf9f4Spatacca 
13183f9bf9f4Spatacca /* Print code that checks that all isl object arguments to "method" are valid
13193f9bf9f4Spatacca  * (not NULL) and throws an exception if they are not.
13203f9bf9f4Spatacca  *
13213f9bf9f4Spatacca  * If checked bindings are being generated,
13223f9bf9f4Spatacca  * then no such check is performed.
13233f9bf9f4Spatacca  */
print_argument_validity_check(const Method & method)13243f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_argument_validity_check(
13253f9bf9f4Spatacca 	const Method &method)
13263f9bf9f4Spatacca {
13273f9bf9f4Spatacca 	int n;
13283f9bf9f4Spatacca 	bool first = true;
13293f9bf9f4Spatacca 
13303f9bf9f4Spatacca 	if (generator.checked)
13313f9bf9f4Spatacca 		return;
13323f9bf9f4Spatacca 
13333f9bf9f4Spatacca 	n = method.num_params();
13343f9bf9f4Spatacca 	for (int i = 0; i < n; ++i) {
13353f9bf9f4Spatacca 		bool is_this;
13363f9bf9f4Spatacca 		ParmVarDecl *param = method.fd->getParamDecl(i);
13373f9bf9f4Spatacca 		string name = param->getName().str();
13383f9bf9f4Spatacca 		const char *name_str = name.c_str();
13393f9bf9f4Spatacca 		QualType type = param->getOriginalType();
13403f9bf9f4Spatacca 
13413f9bf9f4Spatacca 		is_this = i == 0 && method.kind == Method::Kind::member_method;
13423f9bf9f4Spatacca 		if (!is_this && (is_isl_ctx(type) || !is_isl_type(type)))
13433f9bf9f4Spatacca 			continue;
13443f9bf9f4Spatacca 
13453f9bf9f4Spatacca 		if (first)
13463f9bf9f4Spatacca 			osprintf(os, "  if (");
13473f9bf9f4Spatacca 		else
13483f9bf9f4Spatacca 			osprintf(os, " || ");
13493f9bf9f4Spatacca 
13503f9bf9f4Spatacca 		if (is_this)
13513f9bf9f4Spatacca 			osprintf(os, "!ptr");
13523f9bf9f4Spatacca 		else
13533f9bf9f4Spatacca 			osprintf(os, "%s.is_null()", name_str);
13543f9bf9f4Spatacca 
13553f9bf9f4Spatacca 		first = false;
13563f9bf9f4Spatacca 	}
13573f9bf9f4Spatacca 	if (first)
13583f9bf9f4Spatacca 		return;
13593f9bf9f4Spatacca 	osprintf(os, ")\n");
13603f9bf9f4Spatacca 	print_throw_NULL_input(os);
13613f9bf9f4Spatacca }
13623f9bf9f4Spatacca 
1363*a749e09eSMichael Kruse /* Print code for saving a copy of "ctx" in a "saved_ctx" variable.
1364*a749e09eSMichael Kruse  */
print_save_ctx(const std::string & ctx)1365*a749e09eSMichael Kruse void plain_cpp_generator::impl_printer::print_save_ctx(const std::string &ctx)
1366*a749e09eSMichael Kruse {
1367*a749e09eSMichael Kruse 	os << "  auto saved_ctx = " << ctx << ";\n";
1368*a749e09eSMichael Kruse }
1369*a749e09eSMichael Kruse 
13703f9bf9f4Spatacca /* Print code for saving a copy of the isl::ctx available at the start
13713f9bf9f4Spatacca  * of the method "method" in a "saved_ctx" variable,
13723f9bf9f4Spatacca  * for use in exception handling.
13733f9bf9f4Spatacca  *
13743f9bf9f4Spatacca  * If checked bindings are being generated,
13753f9bf9f4Spatacca  * then the "saved_ctx" variable is not needed.
13763f9bf9f4Spatacca  * If "method" is a member function, then obtain the isl_ctx from
13773f9bf9f4Spatacca  * the "this" object.
13783f9bf9f4Spatacca  * If the first argument of the method is an isl::ctx, then use that one.
13793f9bf9f4Spatacca  * Otherwise, save a copy of the isl::ctx associated to the first argument
13803f9bf9f4Spatacca  * of isl object type.
13813f9bf9f4Spatacca  */
print_save_ctx(const Method & method)13823f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_save_ctx(const Method &method)
13833f9bf9f4Spatacca {
13843f9bf9f4Spatacca 	int n;
13853f9bf9f4Spatacca 	ParmVarDecl *param = method.fd->getParamDecl(0);
13863f9bf9f4Spatacca 	QualType type = param->getOriginalType();
13873f9bf9f4Spatacca 
13883f9bf9f4Spatacca 	if (generator.checked)
13893f9bf9f4Spatacca 		return;
1390*a749e09eSMichael Kruse 	if (method.kind == Method::Kind::member_method)
1391*a749e09eSMichael Kruse 		return print_save_ctx("ctx()");
1392*a749e09eSMichael Kruse 	if (is_isl_ctx(type))
1393*a749e09eSMichael Kruse 		return print_save_ctx(param->getName().str());
13943f9bf9f4Spatacca 	n = method.num_params();
13953f9bf9f4Spatacca 	for (int i = 0; i < n; ++i) {
13963f9bf9f4Spatacca 		ParmVarDecl *param = method.fd->getParamDecl(i);
13973f9bf9f4Spatacca 		QualType type = param->getOriginalType();
13983f9bf9f4Spatacca 
13993f9bf9f4Spatacca 		if (!is_isl_type(type))
14003f9bf9f4Spatacca 			continue;
1401*a749e09eSMichael Kruse 		print_save_ctx(param->getName().str() + ".ctx()");
14023f9bf9f4Spatacca 		return;
14033f9bf9f4Spatacca 	}
14043f9bf9f4Spatacca }
14053f9bf9f4Spatacca 
14063f9bf9f4Spatacca /* Print code to make isl not print an error message when an error occurs
14073f9bf9f4Spatacca  * within the current scope (if exceptions are available),
14083f9bf9f4Spatacca  * since the error message will be included in the exception.
14093f9bf9f4Spatacca  * If exceptions are not available, then exception::on_error
14103f9bf9f4Spatacca  * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead.
14113f9bf9f4Spatacca  *
14123f9bf9f4Spatacca  * If checked bindings are being generated,
14133f9bf9f4Spatacca  * then leave it to the user to decide what isl should do on error.
14143f9bf9f4Spatacca  * Otherwise, assume that a valid isl::ctx is available
14153f9bf9f4Spatacca  * in the "saved_ctx" variable,
14163f9bf9f4Spatacca  * e.g., through a prior call to print_save_ctx.
14173f9bf9f4Spatacca  */
print_on_error_continue()14183f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_on_error_continue()
14193f9bf9f4Spatacca {
14203f9bf9f4Spatacca 	if (generator.checked)
14213f9bf9f4Spatacca 		return;
14223f9bf9f4Spatacca 	osprintf(os, "  options_scoped_set_on_error saved_on_error(saved_ctx, "
14233f9bf9f4Spatacca 		     "exception::on_error);\n");
14243f9bf9f4Spatacca }
14253f9bf9f4Spatacca 
14263f9bf9f4Spatacca /* Print code to "os" that checks whether any of the persistent callbacks
14273f9bf9f4Spatacca  * of the class of "method" is set and if it failed with an exception.
14283f9bf9f4Spatacca  * If so, the "eptr" in the corresponding data structure contains the exception
14293f9bf9f4Spatacca  * that was caught and that needs to be rethrown.
14303f9bf9f4Spatacca  * This field is cleared because the callback and its data may get reused.
14313f9bf9f4Spatacca  *
14323f9bf9f4Spatacca  * The check only needs to be generated for member methods since
14333f9bf9f4Spatacca  * an object is needed for any of the persistent callbacks to be set.
14343f9bf9f4Spatacca  */
print_persistent_callback_exceptional_execution_check(ostream & os,const Method & method)14353f9bf9f4Spatacca static void print_persistent_callback_exceptional_execution_check(ostream &os,
14363f9bf9f4Spatacca 	const Method &method)
14373f9bf9f4Spatacca {
14383f9bf9f4Spatacca 	if (method.kind != Method::Kind::member_method)
14393f9bf9f4Spatacca 		return;
14403f9bf9f4Spatacca 
14413f9bf9f4Spatacca 	for (const auto &pcb : method.clazz.persistent_callbacks) {
14423f9bf9f4Spatacca 		auto callback_name = method.clazz.persistent_callback_name(pcb);
14433f9bf9f4Spatacca 
14443f9bf9f4Spatacca 		osprintf(os, "  if (%s_data && %s_data->eptr) {\n",
14453f9bf9f4Spatacca 			callback_name.c_str(), callback_name.c_str());
14463f9bf9f4Spatacca 		osprintf(os, "    std::exception_ptr eptr = %s_data->eptr;\n",
14473f9bf9f4Spatacca 			callback_name.c_str());
14483f9bf9f4Spatacca 		osprintf(os, "    %s_data->eptr = nullptr;\n",
14493f9bf9f4Spatacca 			callback_name.c_str());
14503f9bf9f4Spatacca 		osprintf(os, "    std::rethrow_exception(eptr);\n");
14513f9bf9f4Spatacca 		osprintf(os, "  }\n");
14523f9bf9f4Spatacca 	}
14533f9bf9f4Spatacca }
14543f9bf9f4Spatacca 
14553f9bf9f4Spatacca /* Print code that checks whether the execution of the core of "method"
14563f9bf9f4Spatacca  * was successful.
14573f9bf9f4Spatacca  *
14583f9bf9f4Spatacca  * If checked bindings are being generated,
14593f9bf9f4Spatacca  * then no checks are performed.
14603f9bf9f4Spatacca  *
14613f9bf9f4Spatacca  * Otherwise, first check if any of the callbacks failed with
14623f9bf9f4Spatacca  * an exception.  If so, the "eptr" in the corresponding data structure
14633f9bf9f4Spatacca  * contains the exception that was caught and that needs to be rethrown.
14643f9bf9f4Spatacca  * Then check if the function call failed in any other way and throw
14653f9bf9f4Spatacca  * the appropriate exception.
14663f9bf9f4Spatacca  * In particular, if the return type is isl_stat, isl_bool or isl_size,
14673f9bf9f4Spatacca  * then a negative value indicates a failure.  If the return type
14683f9bf9f4Spatacca  * is an isl type, then a NULL value indicates a failure.
14693f9bf9f4Spatacca  * Assume print_save_ctx has made sure that a valid isl::ctx
14703f9bf9f4Spatacca  * is available in the "ctx" variable.
14713f9bf9f4Spatacca  */
print_exceptional_execution_check(const Method & method)14723f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_exceptional_execution_check(
14733f9bf9f4Spatacca 	const Method &method)
14743f9bf9f4Spatacca {
14753f9bf9f4Spatacca 	bool check_null, check_neg;
14763f9bf9f4Spatacca 	QualType return_type = method.fd->getReturnType();
14773f9bf9f4Spatacca 
14783f9bf9f4Spatacca 	if (generator.checked)
14793f9bf9f4Spatacca 		return;
14803f9bf9f4Spatacca 
14813f9bf9f4Spatacca 	print_persistent_callback_exceptional_execution_check(os, method);
14823f9bf9f4Spatacca 
1483*a749e09eSMichael Kruse 	for (const auto &callback : method.callbacks) {
14843f9bf9f4Spatacca 		std::string name;
14853f9bf9f4Spatacca 
1486*a749e09eSMichael Kruse 		name = callback->getName().str();
14873f9bf9f4Spatacca 		osprintf(os, "  if (%s_data.eptr)\n", name.c_str());
14883f9bf9f4Spatacca 		osprintf(os, "    std::rethrow_exception(%s_data.eptr);\n",
14893f9bf9f4Spatacca 			name.c_str());
14903f9bf9f4Spatacca 	}
14913f9bf9f4Spatacca 
14923f9bf9f4Spatacca 	check_neg = is_isl_neg_error(return_type);
14933f9bf9f4Spatacca 	check_null = is_isl_type(return_type);
14943f9bf9f4Spatacca 	if (!check_null && !check_neg)
14953f9bf9f4Spatacca 		return;
14963f9bf9f4Spatacca 
14973f9bf9f4Spatacca 	if (check_neg)
14983f9bf9f4Spatacca 		osprintf(os, "  if (res < 0)\n");
14993f9bf9f4Spatacca 	else
15003f9bf9f4Spatacca 		osprintf(os, "  if (!res)\n");
15013f9bf9f4Spatacca 	print_throw_last_error(os);
15023f9bf9f4Spatacca }
15033f9bf9f4Spatacca 
15043f9bf9f4Spatacca /* Return a pointer to the appropriate type printer,
15053f9bf9f4Spatacca  * i.e., the regular type printer or the checked type printer
15063f9bf9f4Spatacca  * depending on the setting of this->checked.
15073f9bf9f4Spatacca  */
type_printer()15083f9bf9f4Spatacca std::unique_ptr<cpp_type_printer> plain_cpp_generator::type_printer()
15093f9bf9f4Spatacca {
15103f9bf9f4Spatacca 	cpp_type_printer *printer;
15113f9bf9f4Spatacca 
15123f9bf9f4Spatacca 	if (checked)
15133f9bf9f4Spatacca 		printer = new checked_cpp_type_printer();
15143f9bf9f4Spatacca 	else
15153f9bf9f4Spatacca 		printer = new cpp_type_printer();
15163f9bf9f4Spatacca 
15173f9bf9f4Spatacca 	return std::unique_ptr<cpp_type_printer>(printer);
15183f9bf9f4Spatacca }
15193f9bf9f4Spatacca 
15203f9bf9f4Spatacca /* Return the C++ return type of the method "method".
15213f9bf9f4Spatacca  *
15223f9bf9f4Spatacca  * Use the appropriate type printer.
15233f9bf9f4Spatacca  */
get_return_type(const Method & method)15243f9bf9f4Spatacca std::string plain_cpp_generator::get_return_type(const Method &method)
15253f9bf9f4Spatacca {
15263f9bf9f4Spatacca 	return type_printer()->return_type(method);
15273f9bf9f4Spatacca }
15283f9bf9f4Spatacca 
15293f9bf9f4Spatacca /* Given a method "method" for setting a persistent callback of its class,
15303f9bf9f4Spatacca  * print the implementations of the methods needed for that callback.
15313f9bf9f4Spatacca  *
15323f9bf9f4Spatacca  * In particular, print
15333f9bf9f4Spatacca  * - the implementation of a static inline method
15343f9bf9f4Spatacca  *   for use as the C callback function
15353f9bf9f4Spatacca  * - the definition of a private method for setting the callback function
15363f9bf9f4Spatacca  * - the public method for constructing a new object with the callback set.
15373f9bf9f4Spatacca  */
print_set_persistent_callback(const Method & method)15383f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_set_persistent_callback(
15393f9bf9f4Spatacca 	const Method &method)
15403f9bf9f4Spatacca {
15413f9bf9f4Spatacca 	string fullname = method.fd->getName().str();
15423f9bf9f4Spatacca 	ParmVarDecl *param = persistent_callback_arg(method.fd);
15433f9bf9f4Spatacca 	string pname;
15443f9bf9f4Spatacca 	string callback_name = clazz.persistent_callback_name(method.fd);
15453f9bf9f4Spatacca 
15463f9bf9f4Spatacca 	osprintf(os, "\n");
15473f9bf9f4Spatacca 	print_persistent_callback_prototype(method.fd);
15483f9bf9f4Spatacca 	osprintf(os, "\n");
15493f9bf9f4Spatacca 	osprintf(os, "{\n");
15503f9bf9f4Spatacca 	print_callback_body(2, param, callback_name);
15513f9bf9f4Spatacca 	osprintf(os, "}\n\n");
15523f9bf9f4Spatacca 
15533f9bf9f4Spatacca 	pname = param->getName().str();
15543f9bf9f4Spatacca 	print_persistent_callback_setter_prototype(method.fd);
15553f9bf9f4Spatacca 	osprintf(os, "\n");
15563f9bf9f4Spatacca 	osprintf(os, "{\n");
15573f9bf9f4Spatacca 	print_check_ptr_start("ptr");
15583f9bf9f4Spatacca 	osprintf(os, "  %s_data = std::make_shared<struct %s_data>();\n",
15593f9bf9f4Spatacca 		callback_name.c_str(), callback_name.c_str());
15603f9bf9f4Spatacca 	osprintf(os, "  %s_data->func = %s;\n",
15613f9bf9f4Spatacca 		callback_name.c_str(), pname.c_str());
15623f9bf9f4Spatacca 	osprintf(os, "  ptr = %s(ptr, &%s, %s_data.get());\n",
15633f9bf9f4Spatacca 		fullname.c_str(), callback_name.c_str(), callback_name.c_str());
15643f9bf9f4Spatacca 	print_check_ptr_end("ptr");
15653f9bf9f4Spatacca 	osprintf(os, "}\n\n");
15663f9bf9f4Spatacca 
15673f9bf9f4Spatacca 	print_full_method_header(method);
15683f9bf9f4Spatacca 	osprintf(os, "{\n");
15693f9bf9f4Spatacca 	osprintf(os, "  auto copy = *this;\n");
15703f9bf9f4Spatacca 	osprintf(os, "  copy.set_%s_data(%s);\n",
15713f9bf9f4Spatacca 		callback_name.c_str(), pname.c_str());
15723f9bf9f4Spatacca 	osprintf(os, "  return copy;\n");
15733f9bf9f4Spatacca 	osprintf(os, "}\n");
15743f9bf9f4Spatacca }
15753f9bf9f4Spatacca 
15763f9bf9f4Spatacca /* Print the return statement of the C++ method "method".
15773f9bf9f4Spatacca  *
15783f9bf9f4Spatacca  * The result of the corresponding isl function is returned as a new
15793f9bf9f4Spatacca  * object if the underlying isl function returns an isl_* ptr, as a bool
15803f9bf9f4Spatacca  * if the isl function returns an isl_bool, as void if the isl functions
15813f9bf9f4Spatacca  * returns an isl_stat,
15823f9bf9f4Spatacca  * as std::string if the isl function returns 'const char *', and as
15833f9bf9f4Spatacca  * unmodified return value otherwise.
15843f9bf9f4Spatacca  * If checked C++ bindings are being generated,
15853f9bf9f4Spatacca  * then an isl_bool return type is transformed into a boolean and
15863f9bf9f4Spatacca  * an isl_stat into a stat since no exceptions can be generated
15873f9bf9f4Spatacca  * on negative results from the isl function.
15883f9bf9f4Spatacca  * If the method returns a new instance of the same object type and
15893f9bf9f4Spatacca  * if the class has any persistent callbacks, then the data
15903f9bf9f4Spatacca  * for these callbacks are copied from the original to the new object.
15913f9bf9f4Spatacca  * If "clazz" is a subclass that is based on a type function and
15923f9bf9f4Spatacca  * if the return type corresponds to the superclass data type,
15933f9bf9f4Spatacca  * then it is replaced by the subclass data type.
15943f9bf9f4Spatacca  */
print_method_return(const Method & method)15953f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_method_return(
15963f9bf9f4Spatacca 	const Method &method)
15973f9bf9f4Spatacca {
15983f9bf9f4Spatacca 	QualType return_type = method.fd->getReturnType();
15993f9bf9f4Spatacca 	string rettype_str = generator.get_return_type(method);
16003f9bf9f4Spatacca 	bool returns_super = method.is_subclass_mutator();
16013f9bf9f4Spatacca 
16023f9bf9f4Spatacca 	if (is_isl_type(return_type) ||
16033f9bf9f4Spatacca 		    (generator.checked && is_isl_neg_error(return_type))) {
16043f9bf9f4Spatacca 		osprintf(os, "  return manage(res)");
16053f9bf9f4Spatacca 		if (is_mutator(clazz, method.fd) &&
16063f9bf9f4Spatacca 		    clazz.has_persistent_callbacks())
16073f9bf9f4Spatacca 			osprintf(os, ".copy_callbacks(*this)");
16083f9bf9f4Spatacca 		if (returns_super)
16093f9bf9f4Spatacca 			osprintf(os, ".as<%s>()", rettype_str.c_str());
16103f9bf9f4Spatacca 		osprintf(os, ";\n");
16113f9bf9f4Spatacca 	} else if (is_isl_stat(return_type)) {
16123f9bf9f4Spatacca 		osprintf(os, "  return;\n");
16133f9bf9f4Spatacca 	} else if (is_string(return_type)) {
16143f9bf9f4Spatacca 		osprintf(os, "  std::string tmp(res);\n");
16153f9bf9f4Spatacca 		if (gives(method.fd))
16163f9bf9f4Spatacca 			osprintf(os, "  free(res);\n");
16173f9bf9f4Spatacca 		osprintf(os, "  return tmp;\n");
16183f9bf9f4Spatacca 	} else {
16193f9bf9f4Spatacca 		osprintf(os, "  return res;\n");
16203f9bf9f4Spatacca 	}
16213f9bf9f4Spatacca }
16223f9bf9f4Spatacca 
16233f9bf9f4Spatacca /* Print the header for "method", including the terminating semicolon
16243f9bf9f4Spatacca  * in case of a declaration and a newline.
16253f9bf9f4Spatacca  *
16263f9bf9f4Spatacca  * Use the appropriate type printer to print argument and return types.
16273f9bf9f4Spatacca  */
print_full_method_header(const Method & method)16283f9bf9f4Spatacca void plain_cpp_generator::plain_printer::print_full_method_header(
16293f9bf9f4Spatacca 	const Method &method)
16303f9bf9f4Spatacca {
16313f9bf9f4Spatacca 	auto type_printer = generator.type_printer();
16323f9bf9f4Spatacca 
16333f9bf9f4Spatacca 	print_method_header(method, *type_printer);
16343f9bf9f4Spatacca 
16353f9bf9f4Spatacca 	if (declarations)
16363f9bf9f4Spatacca 		osprintf(os, ";");
16373f9bf9f4Spatacca 	osprintf(os, "\n");
16383f9bf9f4Spatacca }
16393f9bf9f4Spatacca 
16403f9bf9f4Spatacca /* Generate the list of argument types for a callback function of
16413f9bf9f4Spatacca  * type "type".  If "cpp" is set, then generate the C++ type list, otherwise
16423f9bf9f4Spatacca  * the C type list.
16433f9bf9f4Spatacca  *
16443f9bf9f4Spatacca  * Use the appropriate type printer.
16453f9bf9f4Spatacca  * For the plain C++ interface, the argument position is irrelevant,
16463f9bf9f4Spatacca  * so simply pass in -1.
16473f9bf9f4Spatacca  */
generate_callback_args(QualType type,bool cpp)16483f9bf9f4Spatacca string plain_cpp_generator::generate_callback_args(QualType type, bool cpp)
16493f9bf9f4Spatacca {
16503f9bf9f4Spatacca 	return type_printer()->generate_callback_args(-1, type, cpp);
16513f9bf9f4Spatacca }
16523f9bf9f4Spatacca 
16533f9bf9f4Spatacca /* Generate the full cpp type of a callback function of type "type".
16543f9bf9f4Spatacca  *
16553f9bf9f4Spatacca  * Use the appropriate type printer.
16563f9bf9f4Spatacca  * For the plain C++ interface, the argument position is irrelevant,
16573f9bf9f4Spatacca  * so simply pass in -1.
16583f9bf9f4Spatacca  */
generate_callback_type(QualType type)16593f9bf9f4Spatacca string plain_cpp_generator::generate_callback_type(QualType type)
16603f9bf9f4Spatacca {
16613f9bf9f4Spatacca 	return type_printer()->generate_callback_type(-1, type);
16623f9bf9f4Spatacca }
16633f9bf9f4Spatacca 
16643f9bf9f4Spatacca /* Print the call to the C++ callback function "call",
16653f9bf9f4Spatacca  * with the given indentation, wrapped
16663f9bf9f4Spatacca  * for use inside the lambda function that is used as the C callback function,
16673f9bf9f4Spatacca  * in the case where checked C++ bindings are being generated.
16683f9bf9f4Spatacca  *
16693f9bf9f4Spatacca  * In particular, print
16703f9bf9f4Spatacca  *
16713f9bf9f4Spatacca  *        auto ret = @call@;
16723f9bf9f4Spatacca  *        return ret.release();
16733f9bf9f4Spatacca  */
print_wrapped_call_checked(int indent,const string & call)16743f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_wrapped_call_checked(int indent,
16753f9bf9f4Spatacca 	const string &call)
16763f9bf9f4Spatacca {
16773f9bf9f4Spatacca 	osprintf(os, indent, "auto ret = %s;\n", call.c_str());
16783f9bf9f4Spatacca 	osprintf(os, indent, "return ret.release();\n");
16793f9bf9f4Spatacca }
16803f9bf9f4Spatacca 
16813f9bf9f4Spatacca /* Print the call to the C++ callback function "call",
16823f9bf9f4Spatacca  * with the given indentation and with return type "rtype", wrapped
16833f9bf9f4Spatacca  * for use inside the lambda function that is used as the C callback function.
16843f9bf9f4Spatacca  *
16853f9bf9f4Spatacca  * In particular, print
16863f9bf9f4Spatacca  *
16873f9bf9f4Spatacca  *        ISL_CPP_TRY {
16883f9bf9f4Spatacca  *          @call@;
16893f9bf9f4Spatacca  *          return isl_stat_ok;
16903f9bf9f4Spatacca  *        } ISL_CPP_CATCH_ALL {
16913f9bf9f4Spatacca  *          data->eptr = std::current_exception();
16923f9bf9f4Spatacca  *          return isl_stat_error;
16933f9bf9f4Spatacca  *        }
16943f9bf9f4Spatacca  * or
16953f9bf9f4Spatacca  *        ISL_CPP_TRY {
16963f9bf9f4Spatacca  *          auto ret = @call@;
16973f9bf9f4Spatacca  *          return ret ? isl_bool_true : isl_bool_false;
16983f9bf9f4Spatacca  *        } ISL_CPP_CATCH_ALL {
16993f9bf9f4Spatacca  *          data->eptr = std::current_exception();
17003f9bf9f4Spatacca  *          return isl_bool_error;
17013f9bf9f4Spatacca  *        }
17023f9bf9f4Spatacca  * or
17033f9bf9f4Spatacca  *        ISL_CPP_TRY {
17043f9bf9f4Spatacca  *          auto ret = @call@;
17053f9bf9f4Spatacca  *          return ret.release();
17063f9bf9f4Spatacca  *        } ISL_CPP_CATCH_ALL {
17073f9bf9f4Spatacca  *          data->eptr = std::current_exception();
17083f9bf9f4Spatacca  *          return NULL;
17093f9bf9f4Spatacca  *        }
17103f9bf9f4Spatacca  *
17113f9bf9f4Spatacca  * depending on the return type.
17123f9bf9f4Spatacca  *
17133f9bf9f4Spatacca  * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)"
17143f9bf9f4Spatacca  * (if exceptions are available).
17153f9bf9f4Spatacca  *
17163f9bf9f4Spatacca  * If checked C++ bindings are being generated, then
17173f9bf9f4Spatacca  * the call is wrapped differently.
17183f9bf9f4Spatacca  */
print_wrapped_call(int indent,const string & call,QualType rtype)17193f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_wrapped_call(int indent,
17203f9bf9f4Spatacca 	const string &call, QualType rtype)
17213f9bf9f4Spatacca {
17223f9bf9f4Spatacca 	if (generator.checked)
17233f9bf9f4Spatacca 		return print_wrapped_call_checked(indent, call);
17243f9bf9f4Spatacca 
17253f9bf9f4Spatacca 	osprintf(os, indent, "ISL_CPP_TRY {\n");
17263f9bf9f4Spatacca 	if (is_isl_stat(rtype))
17273f9bf9f4Spatacca 		osprintf(os, indent, "  %s;\n", call.c_str());
17283f9bf9f4Spatacca 	else
17293f9bf9f4Spatacca 		osprintf(os, indent, "  auto ret = %s;\n", call.c_str());
17303f9bf9f4Spatacca 	if (is_isl_stat(rtype))
17313f9bf9f4Spatacca 		osprintf(os, indent, "  return isl_stat_ok;\n");
17323f9bf9f4Spatacca 	else if (is_isl_bool(rtype))
17333f9bf9f4Spatacca 		osprintf(os, indent,
17343f9bf9f4Spatacca 			"  return ret ? isl_bool_true : isl_bool_false;\n");
17353f9bf9f4Spatacca 	else
17363f9bf9f4Spatacca 		osprintf(os, indent, "  return ret.release();\n");
17373f9bf9f4Spatacca 	osprintf(os, indent, "} ISL_CPP_CATCH_ALL {\n");
17383f9bf9f4Spatacca 	osprintf(os, indent, "  data->eptr = std::current_exception();\n");
17393f9bf9f4Spatacca 	if (is_isl_stat(rtype))
17403f9bf9f4Spatacca 		osprintf(os, indent, "  return isl_stat_error;\n");
17413f9bf9f4Spatacca 	else if (is_isl_bool(rtype))
17423f9bf9f4Spatacca 		osprintf(os, indent, "  return isl_bool_error;\n");
17433f9bf9f4Spatacca 	else
17443f9bf9f4Spatacca 		osprintf(os, indent, "  return NULL;\n");
17453f9bf9f4Spatacca 	osprintf(os, indent, "}\n");
17463f9bf9f4Spatacca }
17473f9bf9f4Spatacca 
17483f9bf9f4Spatacca /* Print the declaration for a "prefix"_data data structure
17493f9bf9f4Spatacca  * that can be used for passing to a C callback function
17503f9bf9f4Spatacca  * containing a copy of the C++ callback function "param",
17513f9bf9f4Spatacca  * along with an std::exception_ptr that is used to store any
17523f9bf9f4Spatacca  * exceptions thrown in the C++ callback.
17533f9bf9f4Spatacca  *
17543f9bf9f4Spatacca  * If the C callback is of the form
17553f9bf9f4Spatacca  *
17563f9bf9f4Spatacca  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
17573f9bf9f4Spatacca  *
17583f9bf9f4Spatacca  * then the following declaration is printed:
17593f9bf9f4Spatacca  *
17603f9bf9f4Spatacca  *      struct <prefix>_data {
17613f9bf9f4Spatacca  *        std::function<stat(map)> func;
17623f9bf9f4Spatacca  *        std::exception_ptr eptr;
17633f9bf9f4Spatacca  *      }
17643f9bf9f4Spatacca  *
17653f9bf9f4Spatacca  * (without a newline or a semicolon).
17663f9bf9f4Spatacca  *
17673f9bf9f4Spatacca  * The std::exception_ptr object is not added to "prefix"_data
17683f9bf9f4Spatacca  * if checked C++ bindings are being generated.
17693f9bf9f4Spatacca  */
print_callback_data_decl(ParmVarDecl * param,const string & prefix)17703f9bf9f4Spatacca void plain_cpp_generator::plain_printer::print_callback_data_decl(
17713f9bf9f4Spatacca 	ParmVarDecl *param,
17723f9bf9f4Spatacca 	const string &prefix)
17733f9bf9f4Spatacca {
17743f9bf9f4Spatacca 	string cpp_args;
17753f9bf9f4Spatacca 
17763f9bf9f4Spatacca 	cpp_args = generator.generate_callback_type(param->getType());
17773f9bf9f4Spatacca 
17783f9bf9f4Spatacca 	osprintf(os, "  struct %s_data {\n", prefix.c_str());
17793f9bf9f4Spatacca 	osprintf(os, "    %s func;\n", cpp_args.c_str());
17803f9bf9f4Spatacca 	if (!generator.checked)
17813f9bf9f4Spatacca 		osprintf(os, "    std::exception_ptr eptr;\n");
17823f9bf9f4Spatacca 	osprintf(os, "  }");
17833f9bf9f4Spatacca }
17843f9bf9f4Spatacca 
17853f9bf9f4Spatacca /* Given a group of methods with the same name,
17863f9bf9f4Spatacca  * should extra methods be added that take as arguments
17873f9bf9f4Spatacca  * those types that can be converted to the original argument type
17883f9bf9f4Spatacca  * through a unary constructor?
17893f9bf9f4Spatacca  *
17903f9bf9f4Spatacca  * Note that even if this method returns true,
17913f9bf9f4Spatacca  * the extra methods are only printed by the caller
17923f9bf9f4Spatacca  * if exactly one of the methods in the group was originally defined
17933f9bf9f4Spatacca  * in the printed class.
17943f9bf9f4Spatacca  * Signal that they should be printed if the group contains
17953f9bf9f4Spatacca  * both methods originally defined in the printed class and
17963f9bf9f4Spatacca  * methods that have been copied from an ancestor
17973f9bf9f4Spatacca  * by checking whether there are at least two methods in the group.
17983f9bf9f4Spatacca  */
want_descendent_overloads(const function_set & methods)17993f9bf9f4Spatacca bool plain_cpp_generator::plain_printer::want_descendent_overloads(
18003f9bf9f4Spatacca 	const function_set &methods)
18013f9bf9f4Spatacca {
18023f9bf9f4Spatacca 	return methods.size() > 1;
18033f9bf9f4Spatacca }
18043f9bf9f4Spatacca 
1805*a749e09eSMichael Kruse /* Print the header of the constructor for the "id" class
1806*a749e09eSMichael Kruse  * that takes a user object.
1807*a749e09eSMichael Kruse  *
1808*a749e09eSMichael Kruse  * The user object is taken as a std::any.
1809*a749e09eSMichael Kruse  */
print_id_constructor_user_header()1810*a749e09eSMichael Kruse void plain_cpp_generator::plain_printer::print_id_constructor_user_header()
1811*a749e09eSMichael Kruse {
1812*a749e09eSMichael Kruse 	if (declarations)
1813*a749e09eSMichael Kruse 		os << "  inline explicit ";
1814*a749e09eSMichael Kruse 	else
1815*a749e09eSMichael Kruse 		os << "id::";
1816*a749e09eSMichael Kruse 	os << "id(" << generator.isl_namespace() << "ctx ctx, "
1817*a749e09eSMichael Kruse 	   << "const std::string &str, const std::any &any)";
1818*a749e09eSMichael Kruse 	if (declarations)
1819*a749e09eSMichael Kruse 		os << ";";
1820*a749e09eSMichael Kruse 	os << "\n";
1821*a749e09eSMichael Kruse }
1822*a749e09eSMichael Kruse 
1823*a749e09eSMichael Kruse /* Print the header of the "id" method
1824*a749e09eSMichael Kruse  * for retrieving the user object associated to the identifier.
1825*a749e09eSMichael Kruse  * If "optional" is set, the method returns a std::optional user object.
1826*a749e09eSMichael Kruse  * The returned object is of a type specified by template parameter T.
1827*a749e09eSMichael Kruse  */
print_id_user_header(bool optional)1828*a749e09eSMichael Kruse void plain_cpp_generator::plain_printer::print_id_user_header(bool optional)
1829*a749e09eSMichael Kruse {
1830*a749e09eSMichael Kruse 	auto indent = declarations ? "  " : "";
1831*a749e09eSMichael Kruse 	os << indent << "template <class T>\n";
1832*a749e09eSMichael Kruse 	os << indent << (optional ? "std::optional<T> " : "T ");
1833*a749e09eSMichael Kruse 	if (!declarations)
1834*a749e09eSMichael Kruse 		os << "id::";
1835*a749e09eSMichael Kruse 	os << (optional ? "try_" : "");
1836*a749e09eSMichael Kruse 	os << "user() const";
1837*a749e09eSMichael Kruse 	if (declarations)
1838*a749e09eSMichael Kruse 		os << ";";
1839*a749e09eSMichael Kruse 	os << "\n";
1840*a749e09eSMichael Kruse }
1841*a749e09eSMichael Kruse 
1842*a749e09eSMichael Kruse /* Perform printing by "fn" in a context that only gets compiled
1843*a749e09eSMichael Kruse  * by C++17 compilers.
1844*a749e09eSMichael Kruse  */
on_cplusplus17(ostream & os,const std::function<void (void)> & fn)1845*a749e09eSMichael Kruse static void on_cplusplus17(ostream &os, const std::function<void(void)> &fn)
1846*a749e09eSMichael Kruse {
1847*a749e09eSMichael Kruse 	os << "#if __cplusplus >= 201703L\n";
1848*a749e09eSMichael Kruse 	fn();
1849*a749e09eSMichael Kruse 	os << "#endif\n";
1850*a749e09eSMichael Kruse }
1851*a749e09eSMichael Kruse 
1852*a749e09eSMichael Kruse /* Print declarations or definitions of the special methods of the "id" class
1853*a749e09eSMichael Kruse  * that are not automatically derived from the C interface.
1854*a749e09eSMichael Kruse  *
1855*a749e09eSMichael Kruse  * In particular, print a constructor that takes a user pointer
1856*a749e09eSMichael Kruse  * as well as methods for retrieving this user pointer.
1857*a749e09eSMichael Kruse  *
1858*a749e09eSMichael Kruse  * These methods require C++17 features.
1859*a749e09eSMichael Kruse  */
print_special_id()1860*a749e09eSMichael Kruse void plain_cpp_generator::plain_printer::print_special_id()
1861*a749e09eSMichael Kruse {
1862*a749e09eSMichael Kruse 	os << "\n";
1863*a749e09eSMichael Kruse 	on_cplusplus17(os, [this] () {
1864*a749e09eSMichael Kruse 		print_id_constructor_user();
1865*a749e09eSMichael Kruse 		print_id_user(true);
1866*a749e09eSMichael Kruse 		print_id_user(false);
1867*a749e09eSMichael Kruse 	});
1868*a749e09eSMichael Kruse }
1869*a749e09eSMichael Kruse 
1870*a749e09eSMichael Kruse /* Print declarations or definitions of any special methods of this class
1871*a749e09eSMichael Kruse  * not automatically derived from the C interface.
1872*a749e09eSMichael Kruse  *
1873*a749e09eSMichael Kruse  * In particular, print special methods for the "id" class.
1874*a749e09eSMichael Kruse  */
print_special()1875*a749e09eSMichael Kruse void plain_cpp_generator::plain_printer::print_special()
1876*a749e09eSMichael Kruse {
1877*a749e09eSMichael Kruse 	if (clazz.name == "isl_id")
1878*a749e09eSMichael Kruse 		print_special_id();
1879*a749e09eSMichael Kruse }
1880*a749e09eSMichael Kruse 
1881*a749e09eSMichael Kruse /* Print declarations or definitions of the public methods.
1882*a749e09eSMichael Kruse  */
print_public_methods()1883*a749e09eSMichael Kruse void plain_cpp_generator::plain_printer::print_public_methods()
1884*a749e09eSMichael Kruse {
1885*a749e09eSMichael Kruse 	print_public_constructors();
1886*a749e09eSMichael Kruse 	print_constructors();
1887*a749e09eSMichael Kruse 	print_copy_assignment();
1888*a749e09eSMichael Kruse 	print_destructor();
1889*a749e09eSMichael Kruse 	print_ptr();
1890*a749e09eSMichael Kruse 	print_downcast();
1891*a749e09eSMichael Kruse 	print_ctx();
1892*a749e09eSMichael Kruse 	print_method_separator();
1893*a749e09eSMichael Kruse 	print_persistent_callbacks();
1894*a749e09eSMichael Kruse 	print_methods();
1895*a749e09eSMichael Kruse 	print_set_enums();
1896*a749e09eSMichael Kruse 	print_special();
1897*a749e09eSMichael Kruse }
1898*a749e09eSMichael Kruse 
18993f9bf9f4Spatacca /* Print the body of C function callback with the given indentation
19003f9bf9f4Spatacca  * that can be use as an argument to "param" for marshalling
19013f9bf9f4Spatacca  * the corresponding C++ callback.
19023f9bf9f4Spatacca  * The data structure that contains the C++ callback is of type
19033f9bf9f4Spatacca  * "prefix"_data.
19043f9bf9f4Spatacca  *
19053f9bf9f4Spatacca  * For a callback of the form
19063f9bf9f4Spatacca  *
19073f9bf9f4Spatacca  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
19083f9bf9f4Spatacca  *
19093f9bf9f4Spatacca  * the following code is generated:
19103f9bf9f4Spatacca  *
19113f9bf9f4Spatacca  *        auto *data = static_cast<struct <prefix>_data *>(arg_1);
19123f9bf9f4Spatacca  *        ISL_CPP_TRY {
19133f9bf9f4Spatacca  *          stat ret = (data->func)(manage(arg_0));
19143f9bf9f4Spatacca  *          return isl_stat_ok;
19153f9bf9f4Spatacca  *        } ISL_CPP_CATCH_ALL {
19163f9bf9f4Spatacca  *          data->eptr = std::current_exception();
19173f9bf9f4Spatacca  *          return isl_stat_error;
19183f9bf9f4Spatacca  *        }
19193f9bf9f4Spatacca  *
19203f9bf9f4Spatacca  * If checked C++ bindings are being generated, then
19213f9bf9f4Spatacca  * generate the following code:
19223f9bf9f4Spatacca  *
19233f9bf9f4Spatacca  *        auto *data = static_cast<struct <prefix>_data *>(arg_1);
19243f9bf9f4Spatacca  *        stat ret = (data->func)(manage(arg_0));
19253f9bf9f4Spatacca  *        return isl_stat(ret);
19263f9bf9f4Spatacca  */
print_callback_body(int indent,ParmVarDecl * param,const string & prefix)19273f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_callback_body(int indent,
19283f9bf9f4Spatacca 	ParmVarDecl *param, const string &prefix)
19293f9bf9f4Spatacca {
19303f9bf9f4Spatacca 	QualType ptype, rtype;
19313f9bf9f4Spatacca 	string call, last_idx;
19323f9bf9f4Spatacca 	const FunctionProtoType *callback;
19333f9bf9f4Spatacca 	int num_params;
19343f9bf9f4Spatacca 
19353f9bf9f4Spatacca 	ptype = param->getType();
19363f9bf9f4Spatacca 
19373f9bf9f4Spatacca 	callback = extract_prototype(ptype);
19383f9bf9f4Spatacca 	rtype = callback->getReturnType();
19393f9bf9f4Spatacca 	num_params = callback->getNumArgs();
19403f9bf9f4Spatacca 
19413f9bf9f4Spatacca 	last_idx = ::to_string(num_params - 1);
19423f9bf9f4Spatacca 
19433f9bf9f4Spatacca 	call = "(data->func)(";
19443f9bf9f4Spatacca 	for (long i = 0; i < num_params - 1; i++) {
19453f9bf9f4Spatacca 		if (!generator.callback_takes_argument(param, i))
19463f9bf9f4Spatacca 			call += "manage_copy";
19473f9bf9f4Spatacca 		else
19483f9bf9f4Spatacca 			call += "manage";
19493f9bf9f4Spatacca 		call += "(arg_" + ::to_string(i) + ")";
19503f9bf9f4Spatacca 		if (i != num_params - 2)
19513f9bf9f4Spatacca 			call += ", ";
19523f9bf9f4Spatacca 	}
19533f9bf9f4Spatacca 	call += ")";
19543f9bf9f4Spatacca 
19553f9bf9f4Spatacca 	osprintf(os, indent,
19563f9bf9f4Spatacca 		 "auto *data = static_cast<struct %s_data *>(arg_%s);\n",
19573f9bf9f4Spatacca 		 prefix.c_str(), last_idx.c_str());
19583f9bf9f4Spatacca 	print_wrapped_call(indent, call, rtype);
19593f9bf9f4Spatacca }
19603f9bf9f4Spatacca 
19613f9bf9f4Spatacca /* Print the local variables that are needed for a callback argument,
19623f9bf9f4Spatacca  * in particular, print a lambda function that wraps the callback and
19633f9bf9f4Spatacca  * a pointer to the actual C++ callback function.
19643f9bf9f4Spatacca  *
19653f9bf9f4Spatacca  * For a callback of the form
19663f9bf9f4Spatacca  *
19673f9bf9f4Spatacca  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
19683f9bf9f4Spatacca  *
19693f9bf9f4Spatacca  * the following lambda function is generated:
19703f9bf9f4Spatacca  *
19713f9bf9f4Spatacca  *      auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
19723f9bf9f4Spatacca  *        auto *data = static_cast<struct fn_data *>(arg_1);
19733f9bf9f4Spatacca  *        try {
19743f9bf9f4Spatacca  *          stat ret = (data->func)(manage(arg_0));
19753f9bf9f4Spatacca  *          return isl_stat_ok;
19763f9bf9f4Spatacca  *        } catch (...) {
19773f9bf9f4Spatacca  *          data->eptr = std::current_exception();
19783f9bf9f4Spatacca  *          return isl_stat_error;
19793f9bf9f4Spatacca  *        }
19803f9bf9f4Spatacca  *      };
19813f9bf9f4Spatacca  *
19823f9bf9f4Spatacca  * A copy of the std::function C++ callback function is stored in
19833f9bf9f4Spatacca  * a fn_data data structure for passing to the C callback function,
19843f9bf9f4Spatacca  * along with an std::exception_ptr that is used to store any
19853f9bf9f4Spatacca  * exceptions thrown in the C++ callback.
19863f9bf9f4Spatacca  *
19873f9bf9f4Spatacca  *      struct fn_data {
19883f9bf9f4Spatacca  *        std::function<stat(map)> func;
19893f9bf9f4Spatacca  *        std::exception_ptr eptr;
19903f9bf9f4Spatacca  *      } fn_data = { fn };
19913f9bf9f4Spatacca  *
19923f9bf9f4Spatacca  * This std::function object represents the actual user
19933f9bf9f4Spatacca  * callback function together with the locally captured state at the caller.
19943f9bf9f4Spatacca  *
19953f9bf9f4Spatacca  * The lambda function is expected to be used as a C callback function
19963f9bf9f4Spatacca  * where the lambda itself is provided as the function pointer and
19973f9bf9f4Spatacca  * where the user void pointer is a pointer to fn_data.
19983f9bf9f4Spatacca  * The std::function object is extracted from the pointer to fn_data
19993f9bf9f4Spatacca  * inside the lambda function.
20003f9bf9f4Spatacca  *
20013f9bf9f4Spatacca  * The std::exception_ptr object is not added to fn_data
20023f9bf9f4Spatacca  * if checked C++ bindings are being generated.
20033f9bf9f4Spatacca  * The body of the generated lambda function then is as follows:
20043f9bf9f4Spatacca  *
20053f9bf9f4Spatacca  *        stat ret = (data->func)(manage(arg_0));
20063f9bf9f4Spatacca  *        return isl_stat(ret);
20073f9bf9f4Spatacca  *
20083f9bf9f4Spatacca  * If the C callback does not take its arguments, then
20093f9bf9f4Spatacca  * manage_copy is used instead of manage.
20103f9bf9f4Spatacca  */
print_callback_local(ParmVarDecl * param)20113f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_callback_local(ParmVarDecl *param)
20123f9bf9f4Spatacca {
20133f9bf9f4Spatacca 	string pname;
20143f9bf9f4Spatacca 	QualType ptype, rtype;
20153f9bf9f4Spatacca 	string c_args, cpp_args, rettype;
20163f9bf9f4Spatacca 	const FunctionProtoType *callback;
20173f9bf9f4Spatacca 
20183f9bf9f4Spatacca 	pname = param->getName().str();
20193f9bf9f4Spatacca 	ptype = param->getType();
20203f9bf9f4Spatacca 
20213f9bf9f4Spatacca 	c_args = generator.generate_callback_args(ptype, false);
20223f9bf9f4Spatacca 
20233f9bf9f4Spatacca 	callback = extract_prototype(ptype);
20243f9bf9f4Spatacca 	rtype = callback->getReturnType();
20253f9bf9f4Spatacca 	rettype = rtype.getAsString();
20263f9bf9f4Spatacca 
20273f9bf9f4Spatacca 	print_callback_data_decl(param, pname);
20283f9bf9f4Spatacca 	osprintf(os, " %s_data = { %s };\n", pname.c_str(), pname.c_str());
20293f9bf9f4Spatacca 	osprintf(os, "  auto %s_lambda = [](%s) -> %s {\n",
20303f9bf9f4Spatacca 		 pname.c_str(), c_args.c_str(), rettype.c_str());
20313f9bf9f4Spatacca 	print_callback_body(4, param, pname);
20323f9bf9f4Spatacca 	osprintf(os, "  };\n");
20333f9bf9f4Spatacca }
20343f9bf9f4Spatacca 
20353f9bf9f4Spatacca /* Return the C++ counterpart to the isl_bool type.
20363f9bf9f4Spatacca  *
20373f9bf9f4Spatacca  * For the checked C++ bindings this is "boolean".
20383f9bf9f4Spatacca  */
isl_bool() const20393f9bf9f4Spatacca std::string checked_cpp_type_printer::isl_bool() const
20403f9bf9f4Spatacca {
20413f9bf9f4Spatacca 	return "boolean";
20423f9bf9f4Spatacca }
20433f9bf9f4Spatacca 
20443f9bf9f4Spatacca /* Return the C++ counterpart to the isl_bool type.
20453f9bf9f4Spatacca  *
20463f9bf9f4Spatacca  * Use the appropriate type printer.
20473f9bf9f4Spatacca  */
isl_bool2cpp()20483f9bf9f4Spatacca string plain_cpp_generator::isl_bool2cpp()
20493f9bf9f4Spatacca {
20503f9bf9f4Spatacca 	return type_printer()->isl_bool();
20513f9bf9f4Spatacca }
20523f9bf9f4Spatacca 
20533f9bf9f4Spatacca /* Return the C++ counterpart to the isl_stat type.
20543f9bf9f4Spatacca  *
20553f9bf9f4Spatacca  * For the checked C++ bindings this is "stat".
20563f9bf9f4Spatacca  */
isl_stat() const20573f9bf9f4Spatacca string checked_cpp_type_printer::isl_stat() const
20583f9bf9f4Spatacca {
20593f9bf9f4Spatacca 	return "stat";
20603f9bf9f4Spatacca }
20613f9bf9f4Spatacca 
20623f9bf9f4Spatacca /* Return the C++ counterpart to the isl_size type.
20633f9bf9f4Spatacca  *
20643f9bf9f4Spatacca  * For the checked C++ bindings this is "class size".
20653f9bf9f4Spatacca  */
isl_size() const20663f9bf9f4Spatacca string checked_cpp_type_printer::isl_size() const
20673f9bf9f4Spatacca {
20683f9bf9f4Spatacca 	return "class size";
20693f9bf9f4Spatacca }
20703f9bf9f4Spatacca 
20713f9bf9f4Spatacca /* Return the namespace of the generated C++ bindings.
20723f9bf9f4Spatacca  *
20733f9bf9f4Spatacca  * For the checked C++ bindings this is "isl::checked::".
20743f9bf9f4Spatacca  */
isl_namespace() const20753f9bf9f4Spatacca std::string checked_cpp_type_printer::isl_namespace() const
20763f9bf9f4Spatacca {
20773f9bf9f4Spatacca 	return "isl::checked::";
20783f9bf9f4Spatacca }
20793f9bf9f4Spatacca 
20803f9bf9f4Spatacca /* Return the namespace of the generated C++ bindings.
20813f9bf9f4Spatacca  *
20823f9bf9f4Spatacca  * Use the appropriate type printer.
20833f9bf9f4Spatacca  */
isl_namespace()20843f9bf9f4Spatacca string plain_cpp_generator::isl_namespace()
20853f9bf9f4Spatacca {
20863f9bf9f4Spatacca 	return type_printer()->isl_namespace();
20873f9bf9f4Spatacca }
20883f9bf9f4Spatacca 
20893f9bf9f4Spatacca /* Translate parameter or return type "type" to its C++ name counterpart.
20903f9bf9f4Spatacca  *
20913f9bf9f4Spatacca  * Use the appropriate type printer.
20923f9bf9f4Spatacca  * For the plain C++ interface, the argument position is irrelevant,
20933f9bf9f4Spatacca  * so simply pass in -1.
20943f9bf9f4Spatacca  */
param2cpp(QualType type)20953f9bf9f4Spatacca string plain_cpp_generator::param2cpp(QualType type)
20963f9bf9f4Spatacca {
20973f9bf9f4Spatacca 	return type_printer()->param(-1, type);
20983f9bf9f4Spatacca }
2099